Merge commit 'e505f1ebab5a9f698aa94bb583b77eafe93baa6e' into dev-release
diff --git a/build.gradle b/build.gradle index 433b39a..323256b 100644 --- a/build.gradle +++ b/build.gradle
@@ -1939,6 +1939,10 @@ systemProperty 'slow_tests', project.property('slow_tests') } + + if (project.hasProperty('desugar_jdk_json_dir')) { + systemProperty 'desugar_jdk_json_dir', project.property('desugar_jdk_json_dir') + } if (project.hasProperty('desugar_jdk_libs')) { systemProperty 'desugar_jdk_libs', project.property('desugar_jdk_libs') }
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg index a4e4210..65521a9 100644 --- a/infra/config/global/cr-buildbucket.cfg +++ b/infra/config/global/cr-buildbucket.cfg
@@ -425,6 +425,7 @@ name: "kotlin-builder" mixins: "linux" mixins: "normal" + priority: 27 recipe { properties_j: "test_options:[\"--not_used\"]" properties: "test_wrapper:google-scripts/build.py"
diff --git a/src/library_desugar/desugar_jdk_libs_alternative_3.json b/src/library_desugar/desugar_jdk_libs_alternative_3.json index e23a9b8..2b0ffd9 100644 --- a/src/library_desugar/desugar_jdk_libs_alternative_3.json +++ b/src/library_desugar/desugar_jdk_libs_alternative_3.json
@@ -77,12 +77,6 @@ "java.time.": "j$.time.", "java.util.Desugar": "j$.util.Desugar" }, - "backport": { - "java.lang.Double8": "java.lang.Double", - "java.lang.Integer8": "java.lang.Integer", - "java.lang.Long8": "java.lang.Long", - "java.lang.Math8": "java.lang.Math" - }, "retarget_lib_member": { "java.util.Date#toInstant": "java.util.DesugarDate", "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs.json b/src/library_desugar/jdk11/desugar_jdk_libs.json new file mode 100644 index 0000000..b0c751c --- /dev/null +++ b/src/library_desugar/jdk11/desugar_jdk_libs.json
@@ -0,0 +1,257 @@ +{ + "configuration_format_version": 3, + "group_id" : "com.tools.android", + "artifact_id" : "desugar_jdk_libs", + "version": "2.0.0", + "required_compilation_api_level": 26, + "synthesized_library_classes_package_prefix": "j$.", + "support_all_callbacks_from_library": true, + "common_flags": [ + { + "api_level_below_or_equal": 25, + "wrapper_conversion": [ + "java.time.Clock" + ] + }, + { + "api_level_below_or_equal": 23, + "wrapper_conversion": [ + "java.util.PrimitiveIterator$OfDouble", + "java.util.PrimitiveIterator$OfInt", + "java.util.PrimitiveIterator$OfLong", + "java.util.Spliterator", + "java.util.Spliterator$OfDouble", + "java.util.Spliterator$OfInt", + "java.util.Spliterator$OfLong", + "java.util.Spliterator$OfPrimitive", + "java.util.function.BiConsumer", + "java.util.function.BiFunction", + "java.util.function.BiPredicate", + "java.util.function.BinaryOperator", + "java.util.function.Consumer", + "java.util.function.DoubleBinaryOperator", + "java.util.function.DoubleConsumer", + "java.util.function.DoubleFunction", + "java.util.function.DoublePredicate", + "java.util.function.DoubleToIntFunction", + "java.util.function.DoubleToLongFunction", + "java.util.function.DoubleUnaryOperator", + "java.util.function.Function", + "java.util.function.IntBinaryOperator", + "java.util.function.IntConsumer", + "java.util.function.IntFunction", + "java.util.function.IntPredicate", + "java.util.function.IntToDoubleFunction", + "java.util.function.IntToLongFunction", + "java.util.function.IntUnaryOperator", + "java.util.function.LongBinaryOperator", + "java.util.function.LongConsumer", + "java.util.function.LongFunction", + "java.util.function.LongPredicate", + "java.util.function.LongToDoubleFunction", + "java.util.function.LongToIntFunction", + "java.util.function.LongUnaryOperator", + "java.util.function.ObjDoubleConsumer", + "java.util.function.ObjIntConsumer", + "java.util.function.ObjLongConsumer", + "java.util.function.Predicate", + "java.util.function.Supplier", + "java.util.function.ToDoubleFunction", + "java.util.function.ToIntFunction", + "java.util.function.ToLongFunction", + "java.util.function.UnaryOperator", + "java.util.stream.BaseStream", + "java.util.stream.Collector", + "java.util.stream.DoubleStream", + "java.util.stream.IntStream", + "java.util.stream.LongStream", + "java.util.stream.Stream" + ] + } + ], + "library_flags": [ + { + "api_level_below_or_equal": 25, + "rewrite_prefix": { + "j$.time.": "java.time.", + "java.time.": "j$.time.", + "java.util.Desugar": "j$.util.Desugar", + "sun.misc.Desugar": "j$.sun.misc.Desugar", + "jdk.internal.util.Preconditions": "j$.jdk.internal.util.Preconditions" + }, + "retarget_lib_member": { + "java.util.Date#toInstant": "java.util.DesugarDate", + "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar", + "java.util.TimeZone#toZoneId": "java.util.DesugarTimeZone" + }, + "custom_conversion": { + "java.time.ZonedDateTime": "java.time.TimeConversions", + "java.time.LocalDate": "java.time.TimeConversions", + "java.time.Duration": "java.time.TimeConversions", + "java.time.ZoneId": "java.time.TimeConversions", + "java.time.MonthDay": "java.time.TimeConversions", + "java.time.Instant": "java.time.TimeConversions" + } + }, + { + "api_level_below_or_equal": 23, + "rewrite_prefix": { + "j$.util.Optional": "java.util.Optional", + "j$.util.LongSummaryStatistics": "java.util.LongSummaryStatistics", + "j$.util.IntSummaryStatistics": "java.util.IntSummaryStatistics", + "j$.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatistics", + "java.util.stream.": "j$.util.stream.", + "java.util.function.": "j$.util.function.", + "java.util.Comparators": "j$.util.Comparators", + "java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics", + "java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics", + "java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics", + "java.util.Objects": "j$.util.Objects", + "java.util.Optional": "j$.util.Optional", + "java.util.PrimitiveIterator": "j$.util.PrimitiveIterator", + "java.util.SortedSet$1": "j$.util.SortedSet$1", + "java.util.Spliterator": "j$.util.Spliterator", + "java.util.StringJoiner": "j$.util.StringJoiner", + "java.util.Tripwire": "j$.util.Tripwire", + "java.util.concurrent.Helpers": "j$.util.concurrent.Helpers", + "java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom", + "java.util.concurrent.atomic.DesugarAtomic": "j$.util.concurrent.atomic.DesugarAtomic", + "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap", + "java.util.AbstractList": "j$.util.AbstractList", + "java.util.CollSer": "j$.util.CollSer", + "java.util.ImmutableCollections": "j$.util.ImmutableCollections", + "java.util.KeyValueHolder": "j$.util.KeyValueHolder" + }, + "retarget_lib_member": { + "java.util.Arrays#stream": "java.util.DesugarArrays", + "java.util.Arrays#spliterator": "java.util.DesugarArrays", + "java.util.LinkedHashSet#spliterator": "java.util.DesugarLinkedHashSet" + }, + "dont_rewrite": [ + "java.util.Iterator#remove" + ], + "emulate_interface": { + "java.lang.Iterable": "j$.lang.Iterable", + "java.util.Map$Entry": "j$.util.Map$Entry", + "java.util.Collection": "j$.util.Collection", + "java.util.Map": "j$.util.Map", + "java.util.Iterator": "j$.util.Iterator", + "java.util.Comparator": "j$.util.Comparator", + "java.util.List": "j$.util.List", + "java.util.SortedSet": "j$.util.SortedSet", + "java.util.Set": "j$.util.Set", + "java.util.concurrent.ConcurrentMap": "j$.util.concurrent.ConcurrentMap" + }, + "custom_conversion": { + "java.util.Optional": "java.util.OptionalConversions", + "java.util.OptionalDouble": "java.util.OptionalConversions", + "java.util.OptionalInt": "java.util.OptionalConversions", + "java.util.OptionalLong": "java.util.OptionalConversions", + "java.util.LongSummaryStatistics": "java.util.LongSummaryStatisticsConversions", + "java.util.IntSummaryStatistics": "java.util.IntSummaryStatisticsConversions", + "java.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatisticsConversions" + } + } + ], + "program_flags": [ + { + "api_level_below_or_equal": 25, + "rewrite_prefix": { + "java.time.": "j$.time.", + "java.util.Desugar": "j$.util.Desugar" + }, + "retarget_lib_member": { + "java.util.Calendar#toInstant": "java.util.DesugarCalendar", + "java.util.Date#from": "java.util.DesugarDate", + "java.util.Date#toInstant": "java.util.DesugarDate", + "java.util.GregorianCalendar#from": "java.util.DesugarGregorianCalendar", + "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar", + "java.util.TimeZone#getTimeZone": "java.util.DesugarTimeZone", + "java.util.TimeZone#toZoneId": "java.util.DesugarTimeZone" + }, + "custom_conversion": { + "java.time.ZonedDateTime": "java.time.TimeConversions", + "java.time.LocalDate": "java.time.TimeConversions", + "java.time.Duration": "java.time.TimeConversions", + "java.time.ZoneId": "java.time.TimeConversions", + "java.time.MonthDay": "java.time.TimeConversions", + "java.time.Instant": "java.time.TimeConversions" + } + }, + { + "api_level_below_or_equal": 23, + "rewrite_prefix": { + "java.util.stream.": "j$.util.stream.", + "java.util.function.": "j$.util.function.", + "java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics", + "java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics", + "java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics", + "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.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom", + "java.util.concurrent.atomic.DesugarAtomic": "j$.util.concurrent.atomic.DesugarAtomic", + "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap" + }, + "retarget_lib_member": { + "java.util.Arrays#stream": "java.util.DesugarArrays", + "java.util.Arrays#spliterator": "java.util.DesugarArrays", + "java.util.LinkedHashSet#spliterator": "java.util.DesugarLinkedHashSet", + "java.util.concurrent.atomic.AtomicInteger#getAndUpdate": "java.util.concurrent.atomic.DesugarAtomicInteger", + "java.util.concurrent.atomic.AtomicInteger#updateAndGet": "java.util.concurrent.atomic.DesugarAtomicInteger", + "java.util.concurrent.atomic.AtomicInteger#getAndAccumulate": "java.util.concurrent.atomic.DesugarAtomicInteger", + "java.util.concurrent.atomic.AtomicInteger#accumulateAndGet": "java.util.concurrent.atomic.DesugarAtomicInteger", + "java.util.concurrent.atomic.AtomicLong#getAndUpdate": "java.util.concurrent.atomic.DesugarAtomicLong", + "java.util.concurrent.atomic.AtomicLong#updateAndGet": "java.util.concurrent.atomic.DesugarAtomicLong", + "java.util.concurrent.atomic.AtomicLong#getAndAccumulate": "java.util.concurrent.atomic.DesugarAtomicLong", + "java.util.concurrent.atomic.AtomicLong#accumulateAndGet": "java.util.concurrent.atomic.DesugarAtomicLong", + "java.util.concurrent.atomic.AtomicReference#getAndUpdate": "java.util.concurrent.atomic.DesugarAtomicReference", + "java.util.concurrent.atomic.AtomicReference#updateAndGet": "java.util.concurrent.atomic.DesugarAtomicReference", + "java.util.concurrent.atomic.AtomicReference#getAndAccumulate": "java.util.concurrent.atomic.DesugarAtomicReference", + "java.util.concurrent.atomic.AtomicReference#accumulateAndGet": "java.util.concurrent.atomic.DesugarAtomicReference", + "java.util.Collections#synchronizedMap": "java.util.DesugarCollections", + "java.util.Collections#synchronizedSortedMap": "java.util.DesugarCollections" + }, + "dont_rewrite": [ + "java.util.Iterator#remove" + ], + "emulate_interface": { + "java.lang.Iterable": "j$.lang.Iterable", + "java.util.Map$Entry": "j$.util.Map$Entry", + "java.util.Collection": "j$.util.Collection", + "java.util.Map": "j$.util.Map", + "java.util.Iterator": "j$.util.Iterator", + "java.util.Comparator": "j$.util.Comparator", + "java.util.List": "j$.util.List", + "java.util.SortedSet": "j$.util.SortedSet", + "java.util.Set": "j$.util.Set", + "java.util.concurrent.ConcurrentMap": "j$.util.concurrent.ConcurrentMap" + }, + "custom_conversion": { + "java.util.Optional": "java.util.OptionalConversions", + "java.util.OptionalDouble": "java.util.OptionalConversions", + "java.util.OptionalInt": "java.util.OptionalConversions", + "java.util.OptionalLong": "java.util.OptionalConversions", + "java.util.LongSummaryStatistics": "java.util.LongSummaryStatisticsConversions", + "java.util.IntSummaryStatistics": "java.util.IntSummaryStatisticsConversions", + "java.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatisticsConversions" + } + } + ], + "shrinker_config": [ + "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }", + "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }", + "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); private static final java.io.ObjectStreamField[] serialPersistentFields; private static final long serialVersionUID;}", + "-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" + ] +}
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json new file mode 100644 index 0000000..66f3500 --- /dev/null +++ b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
@@ -0,0 +1,260 @@ +{ + "configuration_format_version": 3, + "group_id" : "com.tools.android", + "artifact_id" : "desugar_jdk_libs_alternative_3", + "version": "2.0.0", + "required_compilation_api_level": 26, + "synthesized_library_classes_package_prefix": "j$.", + "support_all_callbacks_from_library": false, + "common_flags": [ + { + "api_level_below_or_equal": 25, + "wrapper_conversion": [ + "java.time.Clock" + ] + }, + { + "api_level_below_or_equal": 23, + "wrapper_conversion": [ + "java.util.PrimitiveIterator$OfDouble", + "java.util.PrimitiveIterator$OfInt", + "java.util.PrimitiveIterator$OfLong", + "java.util.Spliterator", + "java.util.Spliterator$OfDouble", + "java.util.Spliterator$OfInt", + "java.util.Spliterator$OfLong", + "java.util.Spliterator$OfPrimitive", + "java.util.function.BiConsumer", + "java.util.function.BiFunction", + "java.util.function.BiPredicate", + "java.util.function.BinaryOperator", + "java.util.function.Consumer", + "java.util.function.DoubleBinaryOperator", + "java.util.function.DoubleConsumer", + "java.util.function.DoubleFunction", + "java.util.function.DoublePredicate", + "java.util.function.DoubleToIntFunction", + "java.util.function.DoubleToLongFunction", + "java.util.function.DoubleUnaryOperator", + "java.util.function.Function", + "java.util.function.IntBinaryOperator", + "java.util.function.IntConsumer", + "java.util.function.IntFunction", + "java.util.function.IntPredicate", + "java.util.function.IntToDoubleFunction", + "java.util.function.IntToLongFunction", + "java.util.function.IntUnaryOperator", + "java.util.function.LongBinaryOperator", + "java.util.function.LongConsumer", + "java.util.function.LongFunction", + "java.util.function.LongPredicate", + "java.util.function.LongToDoubleFunction", + "java.util.function.LongToIntFunction", + "java.util.function.LongUnaryOperator", + "java.util.function.ObjDoubleConsumer", + "java.util.function.ObjIntConsumer", + "java.util.function.ObjLongConsumer", + "java.util.function.Predicate", + "java.util.function.Supplier", + "java.util.function.ToDoubleFunction", + "java.util.function.ToIntFunction", + "java.util.function.ToLongFunction", + "java.util.function.UnaryOperator", + "java.util.stream.BaseStream", + "java.util.stream.Collector", + "java.util.stream.DoubleStream", + "java.util.stream.IntStream", + "java.util.stream.LongStream", + "java.util.stream.Stream" + ] + } + ], + "library_flags": [ + { + "api_level_below_or_equal": 25, + "rewrite_prefix": { + "j$.time.": "java.time.", + "java.time.": "j$.time.", + "java.util.Desugar": "j$.util.Desugar", + "sun.misc.Desugar": "j$.sun.misc.Desugar", + "jdk.internal.util.Preconditions": "j$.jdk.internal.util.Preconditions" + }, + "retarget_lib_member": { + "java.util.Date#toInstant": "java.util.DesugarDate", + "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar", + "java.util.TimeZone#toZoneId": "java.util.DesugarTimeZone" + }, + "custom_conversion": { + "java.time.ZonedDateTime": "java.time.TimeConversions", + "java.time.LocalDate": "java.time.TimeConversions", + "java.time.Duration": "java.time.TimeConversions", + "java.time.ZoneId": "java.time.TimeConversions", + "java.time.MonthDay": "java.time.TimeConversions", + "java.time.Instant": "java.time.TimeConversions" + } + }, + { + "api_level_below_or_equal": 23, + "rewrite_prefix": { + "j$.util.Optional": "java.util.Optional", + "j$.util.LongSummaryStatistics": "java.util.LongSummaryStatistics", + "j$.util.IntSummaryStatistics": "java.util.IntSummaryStatistics", + "j$.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatistics", + "java.util.stream.": "j$.util.stream.", + "java.util.function.": "j$.util.function.", + "java.util.Comparators": "j$.util.Comparators", + "java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics", + "java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics", + "java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics", + "java.util.Objects": "j$.util.Objects", + "java.util.Optional": "j$.util.Optional", + "java.util.PrimitiveIterator": "j$.util.PrimitiveIterator", + "java.util.SortedSet$1": "j$.util.SortedSet$1", + "java.util.Spliterator": "j$.util.Spliterator", + "java.util.StringJoiner": "j$.util.StringJoiner", + "java.util.Tripwire": "j$.util.Tripwire", + "java.util.concurrent.Helpers": "j$.util.concurrent.Helpers", + "java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom", + "java.util.concurrent.atomic.DesugarAtomic": "j$.util.concurrent.atomic.DesugarAtomic", + "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap", + "java.util.AbstractList": "j$.util.AbstractList", + "java.util.CollSer": "j$.util.CollSer", + "java.util.ImmutableCollections": "j$.util.ImmutableCollections", + "java.util.KeyValueHolder": "j$.util.KeyValueHolder", + "java.io.DesugarBufferedReader": "j$.io.DesugarBufferedReader", + "java.io.UncheckedIOException": "j$.io.UncheckedIOException" + }, + "retarget_lib_member": { + "java.util.Arrays#stream": "java.util.DesugarArrays", + "java.util.Arrays#spliterator": "java.util.DesugarArrays", + "java.util.LinkedHashSet#spliterator": "java.util.DesugarLinkedHashSet", + "java.io.BufferedReader#lines": "java.io.DesugarBufferedReader" + }, + "dont_rewrite": [ + "java.util.Iterator#remove" + ], + "emulate_interface": { + "java.util.Map$Entry": "j$.util.Map$Entry", + "java.util.Collection": "j$.util.Collection", + "java.util.Map": "j$.util.Map", + "java.util.Iterator": "j$.util.Iterator", + "java.util.Comparator": "j$.util.Comparator", + "java.util.List": "j$.util.List", + "java.util.SortedSet": "j$.util.SortedSet", + "java.util.Set": "j$.util.Set", + "java.util.concurrent.ConcurrentMap": "j$.util.concurrent.ConcurrentMap" + }, + "custom_conversion": { + "java.util.Optional": "java.util.OptionalConversions", + "java.util.OptionalDouble": "java.util.OptionalConversions", + "java.util.OptionalInt": "java.util.OptionalConversions", + "java.util.OptionalLong": "java.util.OptionalConversions", + "java.util.LongSummaryStatistics": "java.util.LongSummaryStatisticsConversions", + "java.util.IntSummaryStatistics": "java.util.IntSummaryStatisticsConversions", + "java.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatisticsConversions" + } + } + ], + "program_flags": [ + { + "api_level_below_or_equal": 25, + "rewrite_prefix": { + "java.time.": "j$.time.", + "java.util.Desugar": "j$.util.Desugar" + }, + "retarget_lib_member": { + "java.util.Calendar#toInstant": "java.util.DesugarCalendar", + "java.util.Date#from": "java.util.DesugarDate", + "java.util.Date#toInstant": "java.util.DesugarDate", + "java.util.GregorianCalendar#from": "java.util.DesugarGregorianCalendar", + "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar", + "java.util.TimeZone#getTimeZone": "java.util.DesugarTimeZone", + "java.util.TimeZone#toZoneId": "java.util.DesugarTimeZone" + }, + "custom_conversion": { + "java.time.ZonedDateTime": "java.time.TimeConversions", + "java.time.LocalDate": "java.time.TimeConversions", + "java.time.Duration": "java.time.TimeConversions", + "java.time.ZoneId": "java.time.TimeConversions", + "java.time.MonthDay": "java.time.TimeConversions", + "java.time.Instant": "java.time.TimeConversions" + } + }, + { + "api_level_below_or_equal": 23, + "rewrite_prefix": { + "java.util.stream.": "j$.util.stream.", + "java.util.function.": "j$.util.function.", + "java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics", + "java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics", + "java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics", + "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.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom", + "java.util.concurrent.atomic.DesugarAtomic": "j$.util.concurrent.atomic.DesugarAtomic", + "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap", + "java.io.UncheckedIOException": "j$.io.UncheckedIOException" + }, + "retarget_lib_member": { + "java.util.Arrays#stream": "java.util.DesugarArrays", + "java.util.Arrays#spliterator": "java.util.DesugarArrays", + "java.util.LinkedHashSet#spliterator": "java.util.DesugarLinkedHashSet", + "java.util.concurrent.atomic.AtomicInteger#getAndUpdate": "java.util.concurrent.atomic.DesugarAtomicInteger", + "java.util.concurrent.atomic.AtomicInteger#updateAndGet": "java.util.concurrent.atomic.DesugarAtomicInteger", + "java.util.concurrent.atomic.AtomicInteger#getAndAccumulate": "java.util.concurrent.atomic.DesugarAtomicInteger", + "java.util.concurrent.atomic.AtomicInteger#accumulateAndGet": "java.util.concurrent.atomic.DesugarAtomicInteger", + "java.util.concurrent.atomic.AtomicLong#getAndUpdate": "java.util.concurrent.atomic.DesugarAtomicLong", + "java.util.concurrent.atomic.AtomicLong#updateAndGet": "java.util.concurrent.atomic.DesugarAtomicLong", + "java.util.concurrent.atomic.AtomicLong#getAndAccumulate": "java.util.concurrent.atomic.DesugarAtomicLong", + "java.util.concurrent.atomic.AtomicLong#accumulateAndGet": "java.util.concurrent.atomic.DesugarAtomicLong", + "java.util.concurrent.atomic.AtomicReference#getAndUpdate": "java.util.concurrent.atomic.DesugarAtomicReference", + "java.util.concurrent.atomic.AtomicReference#updateAndGet": "java.util.concurrent.atomic.DesugarAtomicReference", + "java.util.concurrent.atomic.AtomicReference#getAndAccumulate": "java.util.concurrent.atomic.DesugarAtomicReference", + "java.util.concurrent.atomic.AtomicReference#accumulateAndGet": "java.util.concurrent.atomic.DesugarAtomicReference", + "java.util.Collections#synchronizedMap": "java.util.DesugarCollections", + "java.util.Collections#synchronizedSortedMap": "java.util.DesugarCollections", + "java.io.BufferedReader#lines": "java.io.DesugarBufferedReader" + }, + "dont_rewrite": [ + "java.util.Iterator#remove" + ], + "emulate_interface": { + "java.util.Map$Entry": "j$.util.Map$Entry", + "java.util.Collection": "j$.util.Collection", + "java.util.Map": "j$.util.Map", + "java.util.Iterator": "j$.util.Iterator", + "java.util.Comparator": "j$.util.Comparator", + "java.util.List": "j$.util.List", + "java.util.SortedSet": "j$.util.SortedSet", + "java.util.Set": "j$.util.Set", + "java.util.concurrent.ConcurrentMap": "j$.util.concurrent.ConcurrentMap" + }, + "custom_conversion": { + "java.util.Optional": "java.util.OptionalConversions", + "java.util.OptionalDouble": "java.util.OptionalConversions", + "java.util.OptionalInt": "java.util.OptionalConversions", + "java.util.OptionalLong": "java.util.OptionalConversions", + "java.util.LongSummaryStatistics": "java.util.LongSummaryStatisticsConversions", + "java.util.IntSummaryStatistics": "java.util.IntSummaryStatisticsConversions", + "java.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatisticsConversions" + } + } + ], + "shrinker_config": [ + "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }", + "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }", + "-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" + ] +}
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java index b12b467..f0cb3e8 100644 --- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java +++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -618,8 +618,9 @@ * * @param inspection Inspection callback receiving inspectors denoting parts of the output. */ - public void addOutputInspection(Consumer<Inspector> inspection) { + public B addOutputInspection(Consumer<Inspector> inspection) { outputInspections.add(inspection); + return self(); } List<Consumer<Inspector>> getOutputInspections() {
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java index 740984c..a47844f 100644 --- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java +++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -150,11 +150,11 @@ assert method.getHolderType() == clazz.type; CfCode code = null; if (!method.accessFlags.isAbstract() /*&& !method.accessFlags.isNative()*/) { - code = buildEmptyThrowingCfCode(method.method); + code = buildEmptyThrowingCfCode(method.getReference()); } DexEncodedMethod throwingMethod = new DexEncodedMethod( - method.method, + method.getReference(), method.accessFlags, MethodTypeSignature.noSignature(), DexAnnotationSet.empty(), @@ -246,7 +246,7 @@ continue; } ProgramMethod implementationMethod = - implementationClass.lookupProgramMethod(method.method); + implementationClass.lookupProgramMethod(method.getReference()); // Don't include methods which are not implemented by the desugared library. if (supported.test(method) && implementationMethod != null) { supportedMethods.computeIfAbsent(clazz, k -> new ArrayList<>()).add(method); @@ -265,10 +265,10 @@ if (desugaredLibraryConfiguration .getRetargetCoreLibMember() .keySet() - .contains(method.method.name)) { + .contains(method.getReference().name)) { if (desugaredLibraryConfiguration .getRetargetCoreLibMember() - .get(method.method.name) + .get(method.getReference().name) .containsKey(clazz.type)) { if (supported.test(method)) { supportedMethods.computeIfAbsent(clazz, k -> new ArrayList<>()).add(method); @@ -333,8 +333,8 @@ desugaredApisSignatures.add( classBinaryName + '#' - + method.method.name - + method.method.proto.toDescriptorString()); + + method.getReference().name + + method.getReference().proto.toDescriptorString()); } } else { desugaredApisSignatures.add(classBinaryName); @@ -405,7 +405,7 @@ return true; } assert minApiLevel == AndroidApiLevel.B; - return !parallelMethods.contains(method.method); + return !parallelMethods.contains(method.getReference()); }); } @@ -585,7 +585,7 @@ } public String arguments(DexEncodedMethod method) { - DexProto proto = method.method.proto; + DexProto proto = method.getReference().proto; StringBuilder argsBuilder = new StringBuilder(); boolean firstArg = true; int argIndex = method.isVirtualMethod() || method.accessFlags.isConstructor() ? 1 : 0; @@ -685,9 +685,9 @@ builder.appendLiCode( accessFlags(field.accessFlags) + " " - + typeInPackage(field.field.type) + + typeInPackage(field.getReference().type) + " " - + field.field.name); + + field.getReference().name); } } if (!constructors.isEmpty()) { @@ -705,12 +705,12 @@ builder.appendLiCode( accessFlags(method.accessFlags) + " " - + typeInPackage(method.method.proto.returnType) + + typeInPackage(method.getReference().proto.returnType) + " " - + method.method.name + + method.getReference().name + arguments(method)); - if (parallelMethods.contains(method.method)) { - parallelM.add(method.method.name.toString()); + if (parallelMethods.contains(method.getReference())) { + parallelM.add(method.getReference().name.toString()); } } }
diff --git a/src/main/java/com/android/tools/r8/JarDiff.java b/src/main/java/com/android/tools/r8/JarDiff.java index a268496..446791f 100644 --- a/src/main/java/com/android/tools/r8/JarDiff.java +++ b/src/main/java/com/android/tools/r8/JarDiff.java
@@ -145,23 +145,23 @@ private void compareMethods(DexProgramClass class1, DexProgramClass class2) { class1.forEachMethod( method1 -> { - DexEncodedMethod method2 = class2.lookupMethod(method1.method); + DexEncodedMethod method2 = class2.lookupMethod(method1.getReference()); compareMethods(method1, method2); }); class2.forEachMethod( method2 -> { - DexEncodedMethod method1 = class1.lookupMethod(method2.method); + DexEncodedMethod method1 = class1.lookupMethod(method2.getReference()); compareMethods(method1, method2); }); } private void compareMethods(DexEncodedMethod m1, DexEncodedMethod m2) { if (m1 == null) { - System.out.println("Only in " + path2 + ": " + m2.method.toSourceString()); + System.out.println("Only in " + path2 + ": " + m2.getReference().toSourceString()); return; } if (m2 == null) { - System.out.println("Only in " + path1 + ": " + m1.method.toSourceString()); + System.out.println("Only in " + path1 + ": " + m1.getReference().toSourceString()); return; } List<String> code1 = getInstructionStrings(m1); @@ -176,12 +176,19 @@ int before = Math.min(i, this.before); int after = Math.min(j, this.after); int context = before + after; - System.out.println("--- " + path1 + "/" + m1.method.toSmaliString()); - System.out.println("+++ " + path2 + "/" + m2.method.toSmaliString()); + System.out.println("--- " + path1 + "/" + m1.getReference().toSmaliString()); + System.out.println("+++ " + path2 + "/" + m2.getReference().toSmaliString()); System.out.println( - "@@ -" + (i - before) + "," + (length1 + context) - + " +" + (i - before) + "," + (length2 + context) + " @@ " - + m1.method.toSourceString()); + "@@ -" + + (i - before) + + "," + + (length1 + context) + + " +" + + (i - before) + + "," + + (length2 + context) + + " @@ " + + m1.getReference().toSourceString()); for (int k = 0; k < before; k++) { System.out.println(" " + code1.get(i - before + k)); }
diff --git a/src/main/java/com/android/tools/r8/JarSizeCompare.java b/src/main/java/com/android/tools/r8/JarSizeCompare.java index 15e29fa..e520d1b 100644 --- a/src/main/java/com/android/tools/r8/JarSizeCompare.java +++ b/src/main/java/com/android/tools/r8/JarSizeCompare.java
@@ -332,8 +332,9 @@ MethodSignature originalSignature = proguardMap == null ? null - : proguardMap.originalSignatureOf(dexEncodedMethod.method); - MethodSignature signature = MethodSignature.fromDexMethod(dexEncodedMethod.method); + : proguardMap.originalSignatureOf(dexEncodedMethod.getReference()); + MethodSignature signature = + MethodSignature.fromDexMethod(dexEncodedMethod.getReference()); consumer.accept( originalSignature == null ? signature : originalSignature, dexEncodedMethod); }); @@ -346,8 +347,10 @@ programClass.forEachField( dexEncodedField -> { FieldSignature originalSignature = - proguardMap == null ? null : proguardMap.originalSignatureOf(dexEncodedField.field); - FieldSignature signature = FieldSignature.fromDexField(dexEncodedField.field); + proguardMap == null + ? null + : proguardMap.originalSignatureOf(dexEncodedField.getReference()); + FieldSignature signature = FieldSignature.fromDexField(dexEncodedField.getReference()); consumer.accept( originalSignature == null ? signature : originalSignature, dexEncodedField); });
diff --git a/src/main/java/com/android/tools/r8/PrintClassList.java b/src/main/java/com/android/tools/r8/PrintClassList.java index 73cb04d..1530251 100644 --- a/src/main/java/com/android/tools/r8/PrintClassList.java +++ b/src/main/java/com/android/tools/r8/PrintClassList.java
@@ -57,7 +57,7 @@ } private static void printMethod(DexEncodedMethod encodedMethod, ClassNameMapper map) { - DexMethod method = encodedMethod.method; + DexMethod method = encodedMethod.getReference(); if (map != null) { System.out.println(map.originalNameOf(method)); } else { @@ -68,7 +68,7 @@ } private static void printField(DexEncodedField encodedField, ClassNameMapper map) { - DexField field = encodedField.field; + DexField field = encodedField.getReference(); if (map != null) { System.out.println(map.originalNameOf(field)); } else {
diff --git a/src/main/java/com/android/tools/r8/PrintUses.java b/src/main/java/com/android/tools/r8/PrintUses.java index 80b5ec7..926577f 100644 --- a/src/main/java/com/android/tools/r8/PrintUses.java +++ b/src/main/java/com/android/tools/r8/PrintUses.java
@@ -108,9 +108,9 @@ ResolutionResult resolutionResult = appInfo.unsafeResolveMethodDueToDexFormat(method); DexEncodedMethod target = resolutionResult.isVirtualTarget() ? resolutionResult.getSingleTarget() : null; - if (target != null && target.method != method) { + if (target != null && target.getReference() != method) { addType(method.holder); - addMethod(target.method); + addMethod(target.getReference()); } else { addMethod(method); } @@ -124,9 +124,9 @@ @Override public void registerInvokeStatic(DexMethod method) { DexEncodedMethod target = appInfo.unsafeResolveMethodDueToDexFormat(method).getSingleTarget(); - if (target != null && target.method != method) { + if (target != null && target.getReference() != method) { addType(method.holder); - addMethod(target.method); + addMethod(target.getReference()); } else { addMethod(method); } @@ -204,7 +204,7 @@ addType(field.type); DexEncodedField baseField = appInfo.resolveField(field).getResolvedField(); if (baseField != null && baseField.getHolderType() != field.holder) { - field = baseField.field; + field = baseField.getReference(); } addType(field.holder); Set<DexField> typeFields = fields.get(field.holder); @@ -245,7 +245,7 @@ } private void registerField(DexEncodedField field) { - registerTypeReference(field.field.type); + registerTypeReference(field.getReference().type); } private void registerMethod(ProgramMethod method) { @@ -277,10 +277,11 @@ clazz.forEachMethod( method -> { ResolutionResult resolutionResult = - appInfo.resolveMethodOn(superType, method.method, superType != clazz.superType); + appInfo.resolveMethodOn( + superType, method.getReference(), superType != clazz.superType); DexEncodedMethod dexEncodedMethod = resolutionResult.getSingleTarget(); if (dexEncodedMethod != null) { - addMethod(dexEncodedMethod.method); + addMethod(dexEncodedMethod.getReference()); } }); } @@ -428,7 +429,7 @@ if (encodedMethod.accessFlags.isConstructor()) { printConstructorName(encodedMethod); } else { - DexMethod method = encodedMethod.method; + DexMethod method = encodedMethod.getReference(); append(method.proto.returnType.toSourceString()); append(" "); append(method.name.toSourceString()); @@ -467,7 +468,7 @@ } methodDefinitions.add(encodedMethod); } - methodDefinitions.sort(Comparator.comparing(x -> x.method.name.toSourceString())); + methodDefinitions.sort(Comparator.comparing(x -> x.getReference().name.toSourceString())); for (DexEncodedMethod encodedMethod : methodDefinitions) { printMethod(encodedMethod, dexClass.type.toSourceString()); } @@ -506,7 +507,7 @@ void printMethod(DexEncodedMethod encodedMethod, String typeName) { append(typeName + ": "); printNameAndReturn(encodedMethod); - printArguments(encodedMethod.method); + printArguments(encodedMethod.getReference()); appendLine(""); } @@ -578,13 +579,13 @@ append("static "); } printNameAndReturn(encodedMethod); - printArguments(encodedMethod.method); + printArguments(encodedMethod.getReference()); appendLine(";"); } @Override void printPackageNames(List<String> packageNames) { - append("-keeppackagenames " + StringUtils.join(packageNames, ",") + "\n"); + append("-keeppackagenames " + StringUtils.join(",", packageNames) + "\n"); } @Override
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java index b77c8ed..e6cc1f5 100644 --- a/src/main/java/com/android/tools/r8/R8.java +++ b/src/main/java/com/android/tools/r8/R8.java
@@ -46,6 +46,7 @@ import com.android.tools.r8.ir.desugar.BackportedMethodRewriter; import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter; import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter; +import com.android.tools.r8.ir.desugar.RecordRewriter; import com.android.tools.r8.ir.optimize.AssertionsRewriter; import com.android.tools.r8.ir.optimize.MethodPoolCollection; import com.android.tools.r8.ir.optimize.NestReducer; @@ -283,7 +284,7 @@ { ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing); DirectMappedDexApplication application = applicationReader.read(executorService).toDirect(); - MainDexInfo mainDexInfo = applicationReader.readMainDexClasses(application); + MainDexInfo mainDexInfo = applicationReader.readMainDexClassesForR8(application); // Now that the dex-application is fully loaded, close any internal archive providers. inputApp.closeInternalArchiveProviders(); @@ -309,6 +310,9 @@ if (options.enableEnumUnboxing) { EnumUnboxingCfMethods.registerSynthesizedCodeReferences(appView.dexItemFactory()); } + if (options.shouldDesugarRecords()) { + RecordRewriter.registerSynthesizedCodeReferences(appView.dexItemFactory()); + } CfUtilityMethodsForCodeOptimizations.registerSynthesizedCodeReferences( appView.dexItemFactory()); @@ -496,7 +500,7 @@ timing.begin("HorizontalClassMerger"); HorizontalClassMerger merger = new HorizontalClassMerger(appViewWithLiveness); HorizontalClassMergerResult horizontalClassMergerResult = - merger.run(runtimeTypeCheckInfo); + merger.run(runtimeTypeCheckInfo, timing); if (horizontalClassMergerResult != null) { // Must rewrite AppInfoWithLiveness before pruning the merged classes, to ensure that // allocations sites, fields accesses, etc. are correctly transferred to the target
diff --git a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java index d56b873..bc57c25 100644 --- a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java +++ b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
@@ -452,7 +452,7 @@ @Override public void print(CfFrame frame) { - String keys = join(frame.getLocals().keySet(), ","); + String keys = join(",", frame.getLocals().keySet()); String values = join(",", frame.getLocals().values(), this::frameTypeType); String stack = join(",", frame.getStack(), this::frameTypeType); printNewInstruction(
diff --git a/src/main/java/com/android/tools/r8/cf/CfPrinter.java b/src/main/java/com/android/tools/r8/cf/CfPrinter.java index 9862f27..64dd9a5 100644 --- a/src/main/java/com/android/tools/r8/cf/CfPrinter.java +++ b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
@@ -140,7 +140,7 @@ } if (method != null) { builder.append(".method "); - appendMethod(method.method); + appendMethod(method.getReference()); newline(); } builder.append(".limit stack ").append(code.getMaxStack());
diff --git a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java index ec4b22f..90fc9ee 100644 --- a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java +++ b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
@@ -242,7 +242,8 @@ : createInitializedType(code.method().getHolderType()); } else { argumentType = - createInitializedType(code.method().method.proto.parameters.values[argumentIndex]); + createInitializedType( + code.method().getReference().proto.parameters.values[argumentIndex]); } Value outValue = instruction.outValue(); if (outValue.outType().isObject()) {
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java index 21de6ac..df1a88b 100644 --- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java +++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -17,6 +17,7 @@ import com.android.tools.r8.ResourceException; import com.android.tools.r8.StringResource; import com.android.tools.r8.errors.CompilationError; +import com.android.tools.r8.errors.UnsupportedMainDexListUsageDiagnostic; import com.android.tools.r8.graph.ClassKind; import com.android.tools.r8.graph.DexApplication; import com.android.tools.r8.graph.DexClass; @@ -29,6 +30,7 @@ import com.android.tools.r8.graph.JarClassFileReader; import com.android.tools.r8.graph.LazyLoadedDexApplication; import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.origin.Origin; import com.android.tools.r8.shaking.MainDexInfo; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.AndroidApp; @@ -65,6 +67,9 @@ private final Timing timing; private final AndroidApp inputApp; + private boolean hasReadProgramResourcesFromCf = false; + private boolean hasReadProgramResourcesFromDex = false; + public interface ProgramClassConflictResolver { DexProgramClass resolveClassConflict(DexProgramClass a, DexProgramClass b); } @@ -151,7 +156,9 @@ // TODO: try and preload less classes. readProguardMap(proguardMap, builder, executorService, futures); ClassReader classReader = new ClassReader(executorService, futures); - JarClassFileReader<DexProgramClass> jcf = classReader.readSources(); + classReader.readSources(); + hasReadProgramResourcesFromCf = classReader.hasReadProgramResourceFromCf; + hasReadProgramResourcesFromDex = classReader.hasReadProgramResourceFromDex; ThreadUtils.awaitFutures(futures); classReader.initializeLazyClassCollection(builder); for (ProgramResourceProvider provider : inputApp.getProgramResourceProviders()) { @@ -199,17 +206,35 @@ } public MainDexInfo readMainDexClasses(DexApplication app) { + return readMainDexClasses(app, hasReadProgramResourcesFromCf); + } + + public MainDexInfo readMainDexClassesForR8(DexApplication app) { + // Officially R8 only support reading CF program inputs, thus we always generate a deprecated + // diagnostic if main-dex list is used. + return readMainDexClasses(app, true); + } + + private MainDexInfo readMainDexClasses(DexApplication app, boolean emitDeprecatedDiagnostics) { MainDexInfo.Builder builder = MainDexInfo.none().builder(); if (inputApp.hasMainDexList()) { for (StringResource resource : inputApp.getMainDexListResources()) { + if (emitDeprecatedDiagnostics) { + options.reporter.warning(new UnsupportedMainDexListUsageDiagnostic(resource.getOrigin())); + } addToMainDexClasses(app, builder, MainDexListParser.parseList(resource, itemFactory)); } - addToMainDexClasses( - app, - builder, - inputApp.getMainDexClasses().stream() - .map(clazz -> itemFactory.createType(DescriptorUtils.javaTypeToDescriptor(clazz))) - .collect(Collectors.toList())); + if (!inputApp.getMainDexClasses().isEmpty()) { + if (emitDeprecatedDiagnostics) { + options.reporter.warning(new UnsupportedMainDexListUsageDiagnostic(Origin.unknown())); + } + addToMainDexClasses( + app, + builder, + inputApp.getMainDexClasses().stream() + .map(clazz -> itemFactory.createType(DescriptorUtils.javaTypeToDescriptor(clazz))) + .collect(Collectors.toList())); + } } return builder.buildList(); } @@ -291,6 +316,13 @@ // Jar application reader to share across all class readers. private final JarApplicationReader application = new JarApplicationReader(options); + // Flag of which input resource types have flowen into the program classes. + // Note that this is just at the level of the resources having been given. + // It is possible to have, e.g., an empty dex file, so no classes, but this will still be true + // as there was a dex resource. + private boolean hasReadProgramResourceFromCf = false; + private boolean hasReadProgramResourceFromDex = false; + ClassReader(ExecutorService executorService, List<Future<?>> futures) { this.executorService = executorService; this.futures = futures; @@ -298,36 +330,42 @@ private void readDexSources(List<ProgramResource> dexSources, Queue<DexProgramClass> classes) throws IOException, ResourceException { - if (dexSources.size() > 0) { - List<DexParser<DexProgramClass>> dexParsers = new ArrayList<>(dexSources.size()); - int computedMinApiLevel = options.minApiLevel; - for (ProgramResource input : dexSources) { - DexReader dexReader = new DexReader(input); - if (options.passthroughDexCode) { - computedMinApiLevel = validateOrComputeMinApiLevel(computedMinApiLevel, dexReader); - } - dexParsers.add(new DexParser<>(dexReader, PROGRAM, options)); + if (dexSources.isEmpty()) { + return; + } + hasReadProgramResourceFromDex = true; + List<DexParser<DexProgramClass>> dexParsers = new ArrayList<>(dexSources.size()); + int computedMinApiLevel = options.minApiLevel; + for (ProgramResource input : dexSources) { + DexReader dexReader = new DexReader(input); + if (options.passthroughDexCode) { + computedMinApiLevel = validateOrComputeMinApiLevel(computedMinApiLevel, dexReader); } + dexParsers.add(new DexParser<>(dexReader, PROGRAM, options)); + } - options.minApiLevel = computedMinApiLevel; + options.minApiLevel = computedMinApiLevel; + for (DexParser<DexProgramClass> dexParser : dexParsers) { + dexParser.populateIndexTables(); + } + // Read the DexCode items and DexProgramClass items in parallel. + if (!options.skipReadingDexCode) { for (DexParser<DexProgramClass> dexParser : dexParsers) { - dexParser.populateIndexTables(); - } - // Read the DexCode items and DexProgramClass items in parallel. - if (!options.skipReadingDexCode) { - for (DexParser<DexProgramClass> dexParser : dexParsers) { - futures.add( - executorService.submit( - () -> { - dexParser.addClassDefsTo(classes::add); // Depends on Methods, Code items etc. - })); - } + futures.add( + executorService.submit( + () -> { + dexParser.addClassDefsTo(classes::add); // Depends on Methods, Code items etc. + })); } } } - private JarClassFileReader<DexProgramClass> readClassSources( + private void readClassSources( List<ProgramResource> classSources, Queue<DexProgramClass> classes) { + if (classSources.isEmpty()) { + return; + } + hasReadProgramResourceFromCf = true; JarClassFileReader<DexProgramClass> reader = new JarClassFileReader<>(application, classes::add, PROGRAM); // Read classes in parallel. @@ -341,10 +379,9 @@ return null; })); } - return reader; } - JarClassFileReader<DexProgramClass> readSources() throws IOException, ResourceException { + void readSources() throws IOException, ResourceException { Collection<ProgramResource> resources = inputApp.computeAllProgramResources(); List<ProgramResource> dexResources = new ArrayList<>(resources.size()); List<ProgramResource> cfResources = new ArrayList<>(resources.size()); @@ -357,7 +394,7 @@ } } readDexSources(dexResources, programClasses); - return readClassSources(cfResources, programClasses); + readClassSources(cfResources, programClasses); } private <T extends DexClass> ClassProvider<T> buildClassProvider(
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java index cd78995..26bbc5e 100644 --- a/src/main/java/com/android/tools/r8/dex/DexParser.java +++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -12,6 +12,7 @@ import com.android.tools.r8.code.Instruction; import com.android.tools.r8.code.InstructionFactory; import com.android.tools.r8.errors.CompilationError; +import com.android.tools.r8.graph.ApplicationReaderMap; import com.android.tools.r8.graph.ClassAccessFlags; import com.android.tools.r8.graph.ClassKind; import com.android.tools.r8.graph.DexAnnotation; @@ -79,6 +80,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; @@ -992,9 +994,12 @@ private void populateTypes() { DexSection dexSection = lookupSection(Constants.TYPE_TYPE_ID_ITEM); assert verifyOrderOfTypeIds(dexSection); + Map<DexType, DexType> typeMap = ApplicationReaderMap.getTypeMap(options); indexedItems.initializeTypes(dexSection.length); for (int i = 0; i < dexSection.length; i++) { - indexedItems.setType(i, typeAt(i)); + DexType type = typeAt(i); + DexType actualType = typeMap.getOrDefault(type, type); + indexedItems.setType(i, actualType); } }
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java index adfab44..889fc27 100644 --- a/src/main/java/com/android/tools/r8/dex/FileWriter.java +++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -275,25 +275,25 @@ // static methods, as well as public non-abstract (default) // and private instance methods. private void checkInterfaceMethod(DexEncodedMethod method) { - if (application.dexItemFactory.isClassConstructor(method.method)) { + if (application.dexItemFactory.isClassConstructor(method.getReference())) { return; // Class constructor is always OK. } if (method.accessFlags.isStatic()) { if (!options.canUseDefaultAndStaticInterfaceMethods() && !options.testing.allowStaticInterfaceMethodsForPreNApiLevel) { throw options.reporter.fatalError( - new StaticInterfaceMethodDiagnostic(new MethodPosition(method.method))); + new StaticInterfaceMethodDiagnostic(new MethodPosition(method.getReference()))); } } else { if (method.isInstanceInitializer()) { throw new CompilationError( - "Interface must not have constructors: " + method.method.toSourceString()); + "Interface must not have constructors: " + method.getReference().toSourceString()); } if (!method.accessFlags.isAbstract() && !method.accessFlags.isPrivate() && !options.canUseDefaultAndStaticInterfaceMethods()) { throw options.reporter.fatalError( - new DefaultInterfaceMethodDiagnostic(new MethodPosition(method.method))); + new DefaultInterfaceMethodDiagnostic(new MethodPosition(method.getReference()))); } } @@ -302,12 +302,14 @@ return; } throw options.reporter.fatalError( - new PrivateInterfaceMethodDiagnostic(new MethodPosition(method.method))); + new PrivateInterfaceMethodDiagnostic(new MethodPosition(method.getReference()))); } if (!method.accessFlags.isPublic()) { - throw new CompilationError("Interface methods must not be " - + "protected or package private: " + method.method.toSourceString()); + throw new CompilationError( + "Interface methods must not be " + + "protected or package private: " + + method.getReference().toSourceString()); } } @@ -636,32 +638,36 @@ private void writeEncodedFields(List<DexEncodedField> unsortedFields) { List<DexEncodedField> fields = new ArrayList<>(unsortedFields); - fields.sort((a, b) -> a.field.acceptCompareTo(b.field, mapping.getCompareToVisitor())); + fields.sort( + (a, b) -> + a.getReference().acceptCompareTo(b.getReference(), mapping.getCompareToVisitor())); int currentOffset = 0; for (DexEncodedField field : fields) { assert field.validateDexValue(application.dexItemFactory); - int nextOffset = mapping.getOffsetFor(field.field); + int nextOffset = mapping.getOffsetFor(field.getReference()); assert nextOffset - currentOffset >= 0; dest.putUleb128(nextOffset - currentOffset); currentOffset = nextOffset; dest.putUleb128(field.accessFlags.getAsDexAccessFlags()); - desugaredLibraryCodeToKeep.recordField(field.field); + desugaredLibraryCodeToKeep.recordField(field.getReference()); } } private void writeEncodedMethods( Iterable<DexEncodedMethod> unsortedMethods, boolean isSharedSynthetic) { List<DexEncodedMethod> methods = IterableUtils.toNewArrayList(unsortedMethods); - methods.sort((a, b) -> a.method.acceptCompareTo(b.method, mapping.getCompareToVisitor())); + methods.sort( + (a, b) -> + a.getReference().acceptCompareTo(b.getReference(), mapping.getCompareToVisitor())); int currentOffset = 0; for (DexEncodedMethod method : methods) { - int nextOffset = mapping.getOffsetFor(method.method); + int nextOffset = mapping.getOffsetFor(method.getReference()); assert nextOffset - currentOffset >= 0; dest.putUleb128(nextOffset - currentOffset); currentOffset = nextOffset; dest.putUleb128(method.accessFlags.getAsDexAccessFlags()); DexCode code = codeMapping.getCode(method); - desugaredLibraryCodeToKeep.recordMethod(method.method); + desugaredLibraryCodeToKeep.recordMethod(method.getReference()); if (code == null) { assert method.shouldNotHaveCode(); dest.putUleb128(0);
diff --git a/src/main/java/com/android/tools/r8/errors/DuplicateTypesDiagnostic.java b/src/main/java/com/android/tools/r8/errors/DuplicateTypesDiagnostic.java index 1c35883..6aa7234 100644 --- a/src/main/java/com/android/tools/r8/errors/DuplicateTypesDiagnostic.java +++ b/src/main/java/com/android/tools/r8/errors/DuplicateTypesDiagnostic.java
@@ -64,6 +64,6 @@ @Override public String getDiagnosticMessage() { String typeName = DescriptorUtils.descriptorToJavaType(type.getDescriptor()); - return "Type " + typeName + " is defined multiple times: " + StringUtils.join(origins, ", "); + return "Type " + typeName + " is defined multiple times: " + StringUtils.join(", ", origins); } }
diff --git a/src/main/java/com/android/tools/r8/errors/UnsupportedMainDexListUsageDiagnostic.java b/src/main/java/com/android/tools/r8/errors/UnsupportedMainDexListUsageDiagnostic.java new file mode 100644 index 0000000..9bcbcba --- /dev/null +++ b/src/main/java/com/android/tools/r8/errors/UnsupportedMainDexListUsageDiagnostic.java
@@ -0,0 +1,40 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.errors; + +import com.android.tools.r8.Diagnostic; +import com.android.tools.r8.Keep; +import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.position.Position; + +/** + * Diagnostic to issue warnings/errors for unsupported usage of main-dex list. + * + * <p>See b/181858113 for context. + */ +@Keep +public class UnsupportedMainDexListUsageDiagnostic implements Diagnostic { + private final Origin origin; + + public UnsupportedMainDexListUsageDiagnostic(Origin origin) { + this.origin = origin; + } + + @Override + public Origin getOrigin() { + return origin; + } + + @Override + public Position getPosition() { + return Position.UNKNOWN; + } + + @Override + public String getDiagnosticMessage() { + return "Unsupported usage of main-dex list. " + + "The usage of main-dex-list content for the compilation of non-DEX inputs is deprecated. " + + "See issue https://issuetracker.google.com/181858113 for context."; + } +}
diff --git a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java index d96643d..c8c462b 100644 --- a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java +++ b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
@@ -159,6 +159,11 @@ public boolean isInBaseOrSameFeatureAs( DexProgramClass clazz, ProgramDefinition context, SyntheticItems syntheticItems) { + return isInBaseOrSameFeatureAs(clazz.getContextType(), context, syntheticItems); + } + + public boolean isInBaseOrSameFeatureAs( + DexType clazz, ProgramDefinition context, SyntheticItems syntheticItems) { FeatureSplit split = getFeatureSplit(clazz, syntheticItems); return split.isBase() || split == getFeatureSplit(context, syntheticItems); }
diff --git a/src/main/java/com/android/tools/r8/graph/AccessControl.java b/src/main/java/com/android/tools/r8/graph/AccessControl.java index 51ff1e2..cf2c789 100644 --- a/src/main/java/com/android/tools/r8/graph/AccessControl.java +++ b/src/main/java/com/android/tools/r8/graph/AccessControl.java
@@ -25,15 +25,16 @@ public static OptionalBool isClassAccessible( DexClass clazz, - ProgramDefinition context, + Definition context, ClassToFeatureSplitMap classToFeatureSplitMap, SyntheticItems syntheticItems) { if (!clazz.isPublic() && !clazz.getType().isSamePackage(context.getContextType())) { return OptionalBool.FALSE; } if (clazz.isProgramClass() + && context.isProgramDefinition() && !classToFeatureSplitMap.isInBaseOrSameFeatureAs( - clazz.asProgramClass(), context, syntheticItems)) { + clazz.asProgramClass(), context.asProgramDefinition(), syntheticItems)) { return OptionalBool.UNKNOWN; } return OptionalBool.TRUE; @@ -47,7 +48,7 @@ return isMemberAccessible( resolutionResult.getResolutionPair(), resolutionResult.getInitialResolutionHolder(), - context, + context.getContextClass(), appInfo); } @@ -56,13 +57,14 @@ DexClass initialResolutionHolder, ProgramDefinition context, AppView<? extends AppInfoWithClassHierarchy> appView) { - return isMemberAccessible(member, initialResolutionHolder, context, appView.appInfo()); + return isMemberAccessible( + member, initialResolutionHolder, context.getContextClass(), appView.appInfo()); } - public static OptionalBool isMemberAccessible( + static OptionalBool isMemberAccessible( DexClassAndMember<?, ?> member, DexClass initialResolutionHolder, - ProgramDefinition context, + DexClass context, AppInfoWithClassHierarchy appInfo) { AccessFlags<?> memberFlags = member.getDefinition().getAccessFlags(); OptionalBool classAccessibility = @@ -78,25 +80,28 @@ return classAccessibility; } if (memberFlags.isPrivate()) { - if (!isNestMate(member.getHolder(), context.getContextClass())) { + if (!isNestMate(member.getHolder(), context)) { return OptionalBool.FALSE; } return classAccessibility; } - if (member.getHolderType().isSamePackage(context.getContextType())) { + if (member.getHolderType().isSamePackage(context.getType())) { return classAccessibility; } - if (memberFlags.isProtected() - && appInfo.isSubtype(context.getContextType(), member.getHolderType())) { + if (memberFlags.isProtected() && appInfo.isSubtype(context.getType(), member.getHolderType())) { return classAccessibility; } return OptionalBool.FALSE; } - private static boolean isNestMate(DexClass clazz, DexProgramClass context) { + private static boolean isNestMate(DexClass clazz, DexClass context) { if (clazz == context) { return true; } + if (context == null) { + assert false : "context should not be null"; + return false; + } if (!clazz.isInANest() || !context.isInANest()) { return false; }
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java index c8d9834..2ee3013 100644 --- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java +++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -455,7 +455,7 @@ } assert potentialHolder.isInterface(); for (DexEncodedMethod virtualMethod : potentialHolder.virtualMethods()) { - if (virtualMethod.method.hasSameProtoAndName(method.method) + if (virtualMethod.getReference().hasSameProtoAndName(method.getReference()) && virtualMethod.accessFlags.isSameVisibility(method.accessFlags)) { return true; } @@ -711,7 +711,7 @@ // allowed because of nests, a NoSuchMethodError. Which error cannot be determined without // knowing the calling context. if (result.isPrivateMethod() && clazz != initialResolutionHolder) { - return new IllegalAccessOrNoSuchMethodResult(result); + return new IllegalAccessOrNoSuchMethodResult(initialResolutionHolder, result); } return new SingleResolutionResult(initialResolutionHolder, clazz, result); }
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java index 7622121..7321cc0 100644 --- a/src/main/java/com/android/tools/r8/graph/AppView.java +++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -588,11 +588,11 @@ if (!options().isGeneratingClassFiles()) { return false; } - if (cfByteCodePassThrough.contains(method.method)) { + if (cfByteCodePassThrough.contains(method.getReference())) { return true; } return options().testing.cfByteCodePassThrough != null - && options().testing.cfByteCodePassThrough.test(method.method); + && options().testing.cfByteCodePassThrough.test(method.getReference()); } public boolean hasCfByteCodePassThroughMethods() {
diff --git a/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java b/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java new file mode 100644 index 0000000..82b9d7f --- /dev/null +++ b/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
@@ -0,0 +1,31 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.graph; + +import com.android.tools.r8.utils.InternalOptions; +import com.google.common.collect.ImmutableMap; +import java.util.Map; + +public class ApplicationReaderMap { + + public static Map<String, String> getDescriptorMap(InternalOptions options) { + ImmutableMap.Builder<String, String> builder = ImmutableMap.builder(); + if (options.shouldDesugarRecords()) { + builder.put(DexItemFactory.recordTagDescriptorString, DexItemFactory.recordDescriptorString); + } + return builder.build(); + } + + public static Map<DexType, DexType> getTypeMap(InternalOptions options) { + DexItemFactory factory = options.dexItemFactory(); + ImmutableMap.Builder<DexType, DexType> builder = ImmutableMap.builder(); + getDescriptorMap(options) + .forEach( + (k, v) -> { + builder.put(factory.createType(k), factory.createType(v)); + }); + return builder.build(); + } +}
diff --git a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java b/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java index 187402a..a05960f 100644 --- a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java +++ b/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
@@ -27,7 +27,7 @@ public final class AppliedGraphLens extends NonIdentityGraphLens { private final MutableBidirectionalManyToOneRepresentativeMap<DexType, DexType> renamedTypeNames = - new BidirectionalManyToOneRepresentativeHashMap<>(); + BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap(); private final BiMap<DexField, DexField> originalFieldSignatures = HashBiMap.create(); private final BiMap<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create(); @@ -50,7 +50,7 @@ // Record original field signatures. for (DexEncodedField encodedField : clazz.fields()) { - DexField field = encodedField.field; + DexField field = encodedField.getReference(); DexField original = appView.graphLens().getOriginalFieldSignature(field); if (original != field) { DexField existing = originalFieldSignatures.forcePut(field, original); @@ -60,7 +60,7 @@ // Record original method signatures. for (DexEncodedMethod encodedMethod : clazz.methods()) { - DexMethod method = encodedMethod.method; + DexMethod method = encodedMethod.getReference(); DexMethod original = appView.graphLens().getOriginalMethodSignature(method); DexMethod existing = originalMethodSignatures.inverse().get(original); if (existing == null) {
diff --git a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java index 1c30bbf..4ed66d8 100644 --- a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java +++ b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
@@ -128,9 +128,10 @@ void writeField(DexEncodedField field, PrintStream ps) { if (writeFields) { ClassNameMapper naming = application.getProguardMap(); - FieldSignature fieldSignature = naming != null - ? naming.originalSignatureOf(field.field) - : FieldSignature.fromDexField(field.field); + FieldSignature fieldSignature = + naming != null + ? naming.originalSignatureOf(field.getReference()) + : FieldSignature.fromDexField(field.getReference()); writeAnnotations(null, field.annotations(), ps); ps.print(field.accessFlags + " "); ps.print(fieldSignature);
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 71b938f..315bb3e 100644 --- a/src/main/java/com/android/tools/r8/graph/CfCode.java +++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -300,7 +300,7 @@ } // If tree shaking, only keep annotations on kept methods. if (appView.appInfo().hasLiveness() - && !appView.appInfo().withLiveness().isPinned(method.method)) { + && !appView.appInfo().withLiveness().isPinned(method.getReference())) { return false; } return true; @@ -575,7 +575,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.method)) { + && !appView.appInfo().withLiveness().isPinned(encodedMethod.getReference())) { return DexEncodedMethod.NO_PARAMETER_INFO; } @@ -585,7 +585,7 @@ if (!encodedMethod.isStatic()) { localSlotsForParameters.set(nextLocalSlotsForParameters++); } - for (DexType type : encodedMethod.method.proto.parameters.values) { + for (DexType type : encodedMethod.getReference().proto.parameters.values) { localSlotsForParameters.set(nextLocalSlotsForParameters); nextLocalSlotsForParameters += type.isLongType() || type.isDoubleType() ? 2 : 1; } @@ -607,7 +607,7 @@ @Override public void registerArgumentReferences(DexEncodedMethod method, ArgumentUse registry) { - DexProto proto = method.method.proto; + DexProto proto = method.getReference().proto; boolean isStatic = method.accessFlags.isStatic(); int argumentCount = proto.parameters.values.length + (isStatic ? 0 : 1); Int2IntArrayMap indexToNumber = new Int2IntArrayMap(argumentCount); @@ -728,7 +728,7 @@ if (!method.isInstanceInitializer() && appView .graphLens() - .getOriginalMethodSignature(method.method) + .getOriginalMethodSignature(method.getReference()) .isInstanceInitializer(appView.dexItemFactory())) { // We cannot verify instance initializers if they are moved. return StackMapStatus.NOT_PRESENT; @@ -746,7 +746,7 @@ return reportStackMapError( CfCodeStackMapValidatingException.multipleFramesForLabel( origin, - appView.graphLens().getOriginalMethodSignature(method.method), + appView.graphLens().getOriginalMethodSignature(method.getReference()), appView), appView); } @@ -756,7 +756,9 @@ // From b/168212806, it is possible that the first instruction is a frame. return reportStackMapError( CfCodeStackMapValidatingException.unexpectedStackMapFrame( - origin, appView.graphLens().getOriginalMethodSignature(method.method), appView), + origin, + appView.graphLens().getOriginalMethodSignature(method.getReference()), + appView), appView); } } @@ -777,15 +779,17 @@ if (requireStackMapFrame && stateMap.isEmpty()) { return reportStackMapError( CfCodeStackMapValidatingException.noFramesForMethodWithJumps( - origin, appView.graphLens().getOriginalMethodSignature(method.method), appView), + origin, + appView.graphLens().getOriginalMethodSignature(method.getReference()), + appView), appView); } DexType context = appView.graphLens().lookupType(method.getHolderType()); - DexType returnType = appView.graphLens().lookupType(method.method.getReturnType()); + DexType returnType = appView.graphLens().lookupType(method.getReference().getReturnType()); RewrittenPrototypeDescription rewrittenDescription = RewrittenPrototypeDescription.none(); if (applyProtoTypeChanges) { rewrittenDescription = - appView.graphLens().lookupPrototypeChangesForMethodDefinition(method.method); + appView.graphLens().lookupPrototypeChangesForMethodDefinition(method.getReference()); if (!rewrittenDescription.isEmpty() && rewrittenDescription.getRewrittenReturnInfo() != null) { returnType = rewrittenDescription.getRewrittenReturnInfo().getOldType(); @@ -824,7 +828,7 @@ return reportStackMapError( CfCodeStackMapValidatingException.toDiagnostics( origin, - appView.graphLens().getOriginalMethodSignature(method.method), + appView.graphLens().getOriginalMethodSignature(method.getReference()), i, instruction, ex.getMessage(), @@ -889,7 +893,7 @@ initialLocals.put(index++, FrameType.initialized(context)); } ArgumentInfoCollection argumentsInfo = protoTypeChanges.getArgumentInfoCollection(); - DexType[] parameters = method.method.proto.parameters.values; + DexType[] parameters = method.getReference().proto.parameters.values; int originalNumberOfArguments = parameters.length + argumentsInfo.numberOfRemovedArguments()
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java index ad9bf23..d2d763e 100644 --- a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java +++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
@@ -46,17 +46,18 @@ } public List<DexEncodedMethod> sortMethodAnnotations(CompareToVisitor visitor) { - methodAnnotations.sort((a, b) -> a.method.acceptCompareTo(b.method, visitor)); + methodAnnotations.sort((a, b) -> a.getReference().acceptCompareTo(b.getReference(), visitor)); return methodAnnotations; } public List<DexEncodedMethod> sortParameterAnnotations(CompareToVisitor visitor) { - parameterAnnotations.sort((a, b) -> a.method.acceptCompareTo(b.method, visitor)); + parameterAnnotations.sort( + (a, b) -> a.getReference().acceptCompareTo(b.getReference(), visitor)); return parameterAnnotations; } public List<DexEncodedField> sortFieldAnnotations(CompareToVisitor visitor) { - fieldAnnotations.sort((a, b) -> a.field.acceptCompareTo(b.field, visitor)); + fieldAnnotations.sort((a, b) -> a.getReference().acceptCompareTo(b.getReference(), visitor)); return fieldAnnotations; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java index 130dbcf..b2bc948 100644 --- a/src/main/java/com/android/tools/r8/graph/DexClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -10,6 +10,9 @@ import com.android.tools.r8.errors.CompilationError; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.GenericSignature.ClassSignature; +import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature; +import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature; +import com.android.tools.r8.graph.GenericSignature.FormalTypeParameter; import com.android.tools.r8.kotlin.KotlinClassLevelInfo; import com.android.tools.r8.origin.Origin; import com.android.tools.r8.references.ClassReference; @@ -20,6 +23,7 @@ import com.android.tools.r8.utils.TraversalContinuation; import com.google.common.base.MoreObjects; import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Iterators; import com.google.common.collect.Sets; @@ -31,6 +35,7 @@ import java.util.List; import java.util.ListIterator; import java.util.Set; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -257,7 +262,9 @@ if (options.canHaveDalvikAbstractMethodOnNonAbstractClassVerificationBug() && !isAbstract()) { for (DexEncodedMethod method : methods) { assert !method.isAbstract() - : "Non-abstract method on abstract class: `" + method.method.toSourceString() + "`"; + : "Non-abstract method on abstract class: `" + + method.getReference().toSourceString() + + "`"; } } return true; @@ -363,7 +370,7 @@ public boolean definesStaticField(DexField field) { for (DexEncodedField encodedField : staticFields()) { - if (encodedField.field == field) { + if (encodedField.getReference() == field) { return true; } } @@ -427,7 +434,7 @@ private boolean verifyCorrectnessOfFieldHolder(DexEncodedField field) { assert field.getHolderType() == type : "Expected field `" - + field.field.toSourceString() + + field.getReference().toSourceString() + "` to have holder `" + type.toSourceString() + "`"; @@ -444,8 +451,8 @@ private boolean verifyNoDuplicateFields() { Set<DexField> unique = Sets.newIdentityHashSet(); for (DexEncodedField field : fields()) { - boolean changed = unique.add(field.field); - assert changed : "Duplicate field `" + field.field.toSourceString() + "`"; + boolean changed = unique.add(field.getReference()); + assert changed : "Duplicate field `" + field.getReference().toSourceString() + "`"; } return true; } @@ -463,11 +470,11 @@ public DexField lookupUniqueInstanceFieldWithName(DexString name) { DexField field = null; for (DexEncodedField encodedField : instanceFields()) { - if (encodedField.field.name == name) { + if (encodedField.getReference().name == name) { if (field != null) { return null; } - field = encodedField.field; + field = encodedField.getReference(); } } return field; @@ -544,7 +551,7 @@ DexEncodedMethod matchingName = null; DexEncodedMethod signaturePolymorphicMethod = null; for (DexEncodedMethod method : virtualMethods()) { - if (method.method.name == methodName) { + if (method.getReference().name == methodName) { if (matchingName != null) { // The jvm spec, section 5.4.3.3 details that there must be exactly one method with the // given name only. @@ -564,8 +571,8 @@ || method.getHolderType() == factory.varHandleType; return method.accessFlags.isVarargs() && method.accessFlags.isNative() - && method.method.proto.parameters.size() == 1 - && method.method.proto.parameters.values[0] != factory.objectArrayType; + && method.getReference().proto.parameters.size() == 1 + && method.getReference().proto.parameters.values[0] != factory.objectArrayType; } private <D extends DexEncodedMember<D, R>, R extends DexMember<D, R>> D lookupTarget( @@ -704,7 +711,7 @@ public DexEncodedMethod getInitializer(DexType[] parameters) { for (DexEncodedMethod method : directMethods()) { if (method.isInstanceInitializer() - && Arrays.equals(method.method.proto.parameters.values, parameters)) { + && Arrays.equals(method.getReference().proto.parameters.values, parameters)) { return method; } } @@ -778,13 +785,125 @@ Predicate<DexType> ignore, Set<DexType> seen); + public void forEachImmediateInterface(Consumer<DexType> fn) { + for (DexType iface : interfaces.values) { + fn.accept(iface); + } + } + public void forEachImmediateSupertype(Consumer<DexType> fn) { if (superType != null) { fn.accept(superType); } - for (DexType iface : interfaces.values) { - fn.accept(iface); + forEachImmediateInterface(fn); + } + + public boolean validInterfaceSignatures() { + return getClassSignature().superInterfaceSignatures().isEmpty() + || interfaces.values.length == getClassSignature().superInterfaceSignatures.size(); + } + + public void forEachImmediateInterface(BiConsumer<DexType, ClassTypeSignature> consumer) { + assert validInterfaceSignatures(); + + // If there is no generic signature information don't pass any type arguments. + if (getClassSignature().superInterfaceSignatures().isEmpty()) { + forEachImmediateInterface( + superInterface -> + consumer.accept(superInterface, new ClassTypeSignature(superInterface))); + return; } + + Iterator<DexType> interfaceIterator = Arrays.asList(interfaces.values).iterator(); + Iterator<ClassTypeSignature> interfaceSignatureIterator = + getClassSignature().superInterfaceSignatures().iterator(); + + while (interfaceIterator.hasNext()) { + assert interfaceSignatureIterator.hasNext(); + DexType superInterface = interfaceIterator.next(); + ClassTypeSignature superInterfaceSignatures = interfaceSignatureIterator.next(); + consumer.accept(superInterface, superInterfaceSignatures); + } + } + + public void forEachImmediateSupertype(BiConsumer<DexType, ClassTypeSignature> consumer) { + if (superType != null) { + consumer.accept(superType, classSignature.superClassSignature); + } + forEachImmediateInterface(consumer); + } + + public void forEachImmediateInterfaceWithAppliedTypeArguments( + List<FieldTypeSignature> typeArguments, + BiConsumer<DexType, List<FieldTypeSignature>> consumer) { + assert validInterfaceSignatures(); + + // If there is no generic signature information don't pass any type arguments. + if (getClassSignature().superInterfaceSignatures().size() == 0) { + forEachImmediateInterface( + superInterface -> consumer.accept(superInterface, ImmutableList.of())); + return; + } + + Iterator<DexType> interfaceIterator = Arrays.asList(interfaces.values).iterator(); + Iterator<ClassTypeSignature> interfaceSignatureIterator = + getClassSignature().superInterfaceSignatures().iterator(); + + while (interfaceIterator.hasNext()) { + assert interfaceSignatureIterator.hasNext(); + DexType superInterface = interfaceIterator.next(); + ClassTypeSignature superInterfaceSignatures = interfaceSignatureIterator.next(); + + // With no type arguments erase the signatures. + if (typeArguments.isEmpty() && superInterfaceSignatures.hasTypeVariableArguments()) { + consumer.accept(superInterface, ImmutableList.of()); + continue; + } + + consumer.accept(superInterface, applyTypeArguments(superInterfaceSignatures, typeArguments)); + } + assert !interfaceSignatureIterator.hasNext(); + } + + public void forEachImmediateSupertypeWithAppliedTypeArguments( + List<FieldTypeSignature> typeArguments, + BiConsumer<DexType, List<FieldTypeSignature>> consumer) { + if (superType != null) { + consumer.accept( + superType, applyTypeArguments(getClassSignature().superClassSignature, typeArguments)); + } + forEachImmediateInterfaceWithAppliedTypeArguments(typeArguments, consumer); + } + + private List<FieldTypeSignature> applyTypeArguments( + ClassTypeSignature superInterfaceSignatures, List<FieldTypeSignature> appliedTypeArguments) { + ImmutableList.Builder<FieldTypeSignature> superTypeArgumentsBuilder = ImmutableList.builder(); + if (superInterfaceSignatures.type.toSourceString().equals("java.util.Map")) { + System.currentTimeMillis(); + } + superInterfaceSignatures + .typeArguments() + .forEach( + typeArgument -> { + if (typeArgument.isTypeVariableSignature()) { + for (int i = 0; i < getClassSignature().getFormalTypeParameters().size(); i++) { + FormalTypeParameter formalTypeParameter = + getClassSignature().getFormalTypeParameters().get(i); + if (formalTypeParameter + .getName() + .equals(typeArgument.asTypeVariableSignature().typeVariable())) { + if (i >= appliedTypeArguments.size()) { + assert false; + } else { + superTypeArgumentsBuilder.add(appliedTypeArguments.get(i)); + } + } + } + } else { + superTypeArgumentsBuilder.add(typeArgument); + } + }); + return superTypeArgumentsBuilder.build(); } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java index 32743f0..09bc3b7 100644 --- a/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java +++ b/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
@@ -63,11 +63,11 @@ } public DexDebugEntryBuilder(DexEncodedMethod method, DexItemFactory factory) { - assert method != null && method.method != null; - this.method = method.method; + assert method != null && method.getReference() != null; + this.method = method.getReference(); positionState = new DexDebugPositionState( - method.getCode().asDexCode().getDebugInfo().startLine, method.method); + method.getCode().asDexCode().getDebugInfo().startLine, method.getReference()); DexCode code = method.getCode().asDexCode(); DexDebugInfo info = code.getDebugInfo(); int argumentRegister = code.registerSize - code.incomingRegisterSize; @@ -77,7 +77,7 @@ startArgument(argumentRegister, name, type); argumentRegister += ValueType.fromDexType(type).requiredRegisters(); } - DexType[] types = method.method.proto.parameters.values; + DexType[] types = method.getReference().proto.parameters.values; DexString[] names = info.parameters; for (int i = 0; i < types.length; i++) { // If null, the parameter has a parameterized type and the local is introduced in the stream.
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java index f166e3c..bdfe991 100644 --- a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java +++ b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
@@ -110,7 +110,7 @@ if (startLine == NO_LINE_INFO) { return null; } - DexString[] params = new DexString[method.method.getArity()]; + DexString[] params = new DexString[method.getReference().getArity()]; if (arguments != null) { assert params.length == arguments.size(); for (int i = 0; i < arguments.size(); i++) { @@ -158,7 +158,7 @@ private void startArgument(Argument argument) { if (arguments == null) { - arguments = new ArrayList<>(method.method.getArity()); + arguments = new ArrayList<>(method.getReference().getArity()); } if (!argument.outValue().isThis()) { arguments.add(argument.getLocalInfo());
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java index 1a2b411..65bc4fb 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -31,7 +31,6 @@ implements StructuralItem<DexEncodedField> { public static final DexEncodedField[] EMPTY_ARRAY = {}; - public final DexField field; public final FieldAccessFlags accessFlags; private DexValue staticValue; private final boolean deprecated; @@ -42,10 +41,10 @@ private KotlinFieldLevelInfo kotlinMemberInfo = NO_KOTLIN_INFO; private static void specify(StructuralSpecification<DexEncodedField, ?> spec) { - spec.withItem(f -> f.field) - .withItem(f -> f.accessFlags) + spec.withItem(DexEncodedField::getReference) + .withItem(DexEncodedField::getAccessFlags) .withNullableItem(f -> f.staticValue) - .withBool(f -> f.deprecated) + .withBool(DexEncodedField::isDeprecated) // TODO(b/171867022): The generic signature should be part of the definition. .withAssert(f -> f.genericSignature.hasNoSignature()); // TODO(b/171867022): Should the optimization info and member info be part of the definition? @@ -82,8 +81,7 @@ DexValue staticValue, boolean deprecated, boolean d8R8Synthesized) { - super(annotations, d8R8Synthesized); - this.field = field; + super(field, annotations, d8R8Synthesized); this.accessFlags = accessFlags; this.staticValue = staticValue; this.deprecated = deprecated; @@ -103,7 +101,7 @@ } public DexType type() { - return field.type; + return getReference().type; } public boolean isDeprecated() { @@ -111,8 +109,8 @@ } public boolean isProgramField(DexDefinitionSupplier definitions) { - if (field.holder.isClassType()) { - DexClass clazz = definitions.definitionFor(field.holder); + if (getReference().holder.isClassType()) { + DexClass clazz = definitions.definitionFor(getReference().holder); return clazz != null && clazz.isProgramClass(); } return false; @@ -158,22 +156,17 @@ @Override public String toString() { - return "Encoded field " + field; + return "Encoded field " + getReference(); } @Override public String toSmaliString() { - return field.toSmaliString(); + return getReference().toSmaliString(); } @Override public String toSourceString() { - return field.toSourceString(); - } - - @Override - public DexField getReference() { - return field; + return getReference().toSourceString(); } public DexType getType() { @@ -201,7 +194,7 @@ public ProgramField asProgramField(DexDefinitionSupplier definitions) { assert getHolderType().isClassType(); - DexProgramClass clazz = asProgramClassOrNull(definitions.definitionForHolder(field)); + DexProgramClass clazz = asProgramClassOrNull(definitions.definitionForHolder(getReference())); if (clazz != null) { return new ProgramField(clazz, this); } @@ -264,7 +257,7 @@ public DexValue getStaticValue() { assert accessFlags.isStatic(); - return staticValue == null ? DexValue.defaultForType(field.type) : staticValue; + return staticValue == null ? DexValue.defaultForType(getReference().type) : staticValue; } /** @@ -277,7 +270,7 @@ boolean isWritten = appView.appInfo().isFieldWrittenByFieldPutInstruction(this); if (!isWritten) { // Since the field is not written, we can simply return the default value for the type. - DexValue value = isStatic() ? getStaticValue() : DexValue.defaultForType(field.type); + DexValue value = isStatic() ? getStaticValue() : DexValue.defaultForType(getReference().type); return value.asConstInstruction(appView, code, local); } @@ -286,11 +279,11 @@ if (abstractValue.isSingleValue()) { SingleValue singleValue = abstractValue.asSingleValue(); if (singleValue.isSingleFieldValue() - && singleValue.asSingleFieldValue().getField() == field) { + && singleValue.asSingleFieldValue().getField() == getReference()) { return null; } if (singleValue.isMaterializableInContext(appView, code.context())) { - TypeElement type = TypeElement.fromDexType(field.type, maybeNull(), appView); + TypeElement type = TypeElement.fromDexType(getReference().type, maybeNull(), appView); return singleValue.createMaterializingInstruction( appView, code, TypeAndLocalInfoSupplier.create(type, local)); } @@ -299,12 +292,12 @@ // The only way to figure out whether the static value contains the final value is ensure the // value is not the default or check that <clinit> is not present. if (accessFlags.isFinal() && isStatic()) { - DexClass clazz = appView.definitionFor(field.holder); + DexClass clazz = appView.definitionFor(getReference().holder); if (clazz == null || clazz.hasClassInitializer()) { return null; } DexValue staticValue = getStaticValue(); - if (!staticValue.isDefault(field.type)) { + if (!staticValue.isDefault(getReference().type)) { return staticValue.asConstInstruction(appView, code, local); } } @@ -317,7 +310,7 @@ } public DexEncodedField toTypeSubstitutedField(DexField field, Consumer<Builder> consumer) { - if (this.field == field) { + if (this.getReference() == field) { return this; } return builder(this).setField(field).apply(consumer).build(); @@ -327,12 +320,13 @@ if (!accessFlags.isStatic() || staticValue == null) { return true; } - if (field.type.isPrimitiveType()) { - assert staticValue.getType(factory) == field.type - : "Static " + field + " has invalid static value " + staticValue + "."; + if (getReference().type.isPrimitiveType()) { + assert staticValue.getType(factory) == getReference().type + : "Static " + getReference() + " has invalid static value " + staticValue + "."; } if (staticValue.isDexValueNull()) { - assert field.type.isReferenceType() : "Static " + field + " has invalid null static value."; + assert getReference().type.isReferenceType() + : "Static " + getReference() + " has invalid null static value."; } // TODO(b/150593449): Support non primitive DexValue (String, enum) and add assertions. return true; @@ -369,7 +363,7 @@ Builder(DexEncodedField from) { // Copy all the mutable state of a DexEncodedField here. - field = from.field; + field = from.getReference(); accessFlags = from.accessFlags.copy(); // TODO(b/169923358): Consider removing the fieldSignature here. genericSignature = from.getGenericSignature();
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java index 7d66bb6..0074842 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
@@ -16,8 +16,11 @@ // set. private final boolean d8R8Synthesized; - public DexEncodedMember(DexAnnotationSet annotations, boolean d8R8Synthesized) { + private final R reference; + + public DexEncodedMember(R reference, DexAnnotationSet annotations, boolean d8R8Synthesized) { super(annotations); + this.reference = reference; this.d8R8Synthesized = d8R8Synthesized; } @@ -32,7 +35,9 @@ } @Override - public abstract R getReference(); + public R getReference() { + return reference; + } public boolean isD8R8Synthesized() { return d8R8Synthesized;
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java index 470bee9..d387d77 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -150,7 +150,6 @@ public static final Int2ReferenceMap<DebugLocalInfo> NO_PARAMETER_INFO = new Int2ReferenceArrayMap<>(0); - public final DexMethod method; public final MethodAccessFlags accessFlags; public final boolean deprecated; public ParameterAnnotationsList parameterAnnotationsList; @@ -311,8 +310,7 @@ boolean d8R8Synthesized, CfVersion classFileVersion, boolean deprecated) { - super(annotations, d8R8Synthesized); - this.method = method; + super(method, annotations, d8R8Synthesized); this.accessFlags = accessFlags; this.deprecated = deprecated; this.genericSignature = genericSignature; @@ -383,12 +381,6 @@ return getReference().getProto(); } - @Override - public DexMethod getReference() { - checkIfObsolete(); - return method; - } - public DexType getParameter(int index) { return getReference().getParameter(index); } @@ -398,11 +390,11 @@ } public DexMethodSignature getSignature() { - return new DexMethodSignature(method); + return new DexMethodSignature(getReference()); } public DexType returnType() { - return method.proto.returnType; + return getReference().proto.returnType; } public ParameterAnnotationsList liveParameterAnnotations(AppView<AppInfoWithLiveness> appView) { @@ -420,19 +412,19 @@ assert isLibraryMethodOverride.isPossiblyFalse() || this.isLibraryMethodOverride.isPossiblyTrue() : "Method `" - + method.toSourceString() + + getReference().toSourceString() + "` went from not overriding a library method to overriding a library method"; assert isLibraryMethodOverride.isPossiblyTrue() || this.isLibraryMethodOverride.isPossiblyFalse() : "Method `" - + method.toSourceString() + + getReference().toSourceString() + "` went from overriding a library method to not overriding a library method"; this.isLibraryMethodOverride = isLibraryMethodOverride; } public boolean isProgramMethod(DexDefinitionSupplier definitions) { - if (method.holder.isClassType()) { - DexClass clazz = definitions.definitionFor(method.holder); + if (getReference().holder.isClassType()) { + DexClass clazz = definitions.definitionFor(getReference().holder); return clazz != null && clazz.isProgramClass(); } return false; @@ -444,8 +436,8 @@ } public DexClassAndMethod asDexClassAndMethod(DexDefinitionSupplier definitions) { - assert method.holder.isClassType(); - DexClass clazz = definitions.definitionForHolder(method); + assert getReference().holder.isClassType(); + DexClass clazz = definitions.definitionForHolder(getReference()); if (clazz != null) { return DexClassAndMethod.create(clazz, this); } @@ -453,8 +445,8 @@ } public ProgramMethod asProgramMethod(DexDefinitionSupplier definitions) { - assert method.holder.isClassType(); - DexProgramClass clazz = asProgramClassOrNull(definitions.definitionForHolder(method)); + assert getReference().holder.isClassType(); + DexProgramClass clazz = asProgramClassOrNull(definitions.definitionForHolder(getReference())); if (clazz != null) { return new ProgramMethod(clazz, this); } @@ -530,7 +522,7 @@ public boolean isDefaultInitializer() { checkIfObsolete(); - return isInstanceInitializer() && method.proto.parameters.isEmpty(); + return isInstanceInitializer() && getReference().proto.parameters.isEmpty(); } public boolean isClassInitializer() { @@ -698,28 +690,28 @@ return true; case PROCESSED_INLINING_CANDIDATE_SUBCLASS: - if (appInfo.isSubtype(containerType, method.holder)) { + if (appInfo.isSubtype(containerType, getReference().holder)) { return true; } whyAreYouNotInliningReporter.reportCallerNotSubtype(); return false; case PROCESSED_INLINING_CANDIDATE_SAME_PACKAGE: - if (containerType.isSamePackage(method.holder)) { + if (containerType.isSamePackage(getReference().holder)) { return true; } whyAreYouNotInliningReporter.reportCallerNotSamePackage(); return false; case PROCESSED_INLINING_CANDIDATE_SAME_NEST: - if (NestUtils.sameNest(containerType, method.holder, appInfo)) { + if (NestUtils.sameNest(containerType, getReference().holder, appInfo)) { return true; } whyAreYouNotInliningReporter.reportCallerNotSameNest(); return false; case PROCESSED_INLINING_CANDIDATE_SAME_CLASS: - if (containerType == method.holder) { + if (containerType == getReference().holder) { return true; } whyAreYouNotInliningReporter.reportCallerNotSameClass(); @@ -808,7 +800,7 @@ @Override public String toString() { checkIfObsolete(); - return "Encoded method " + method; + return "Encoded method " + getReference(); } @Override @@ -869,7 +861,7 @@ public String qualifiedName() { checkIfObsolete(); - return method.qualifiedName(); + return getReference().qualifiedName(); } public String descriptor() { @@ -881,11 +873,11 @@ checkIfObsolete(); StringBuilder builder = new StringBuilder(); builder.append("("); - for (DexType type : method.proto.parameters.values) { + for (DexType type : getReference().proto.parameters.values) { builder.append(namingLens.lookupDescriptor(type).toString()); } builder.append(")"); - builder.append(namingLens.lookupDescriptor(method.proto.returnType).toString()); + builder.append(namingLens.lookupDescriptor(getReference().proto.returnType).toString()); return builder.toString(); } @@ -903,8 +895,8 @@ builder.append(".method "); builder.append(accessFlags.toSmaliString()); builder.append(" "); - builder.append(method.name.toSmaliString()); - builder.append(method.proto.toSmaliString()); + builder.append(getReference().name.toSmaliString()); + builder.append(getReference().proto.toSmaliString()); builder.append("\n"); if (code != null) { DexCode dexCode = code.asDexCode(); @@ -920,7 +912,7 @@ @Override public String toSourceString() { checkIfObsolete(); - return method.toSourceString(); + return getReference().toSourceString(); } public DexEncodedMethod toAbstractMethod() { @@ -946,7 +938,7 @@ offset += instruction.getSize(); } int requiredArgRegisters = accessFlags.isStatic() ? 0 : 1; - for (DexType type : method.proto.parameters.values) { + for (DexType type : getReference().proto.parameters.values) { requiredArgRegisters += ValueType.fromDexType(type).requiredRegisters(); } return new DexCode( @@ -998,7 +990,7 @@ } public CfCode buildEmptyThrowingCfCode() { - return buildEmptyThrowingCfCode(method); + return buildEmptyThrowingCfCode(getReference()); } public static CfCode buildEmptyThrowingCfCode(DexMethod method) { @@ -1034,9 +1026,9 @@ } instructions[i] = new CfReturn(ValueType.INT); return new CfCode( - method.holder, + getReference().holder, 1 + BooleanUtils.intValue(negate), - method.getArity() + 1, + getReference().getArity() + 1, Arrays.asList(instructions), Collections.emptyList(), Collections.emptyList()); @@ -1076,10 +1068,13 @@ private DexEncodedMethod toMethodThatLogsErrorDexCode(DexItemFactory itemFactory) { checkIfObsolete(); - Signature signature = MethodSignature.fromDexMethod(method); + Signature signature = MethodSignature.fromDexMethod(getReference()); DexString message = itemFactory.createString( - CONFIGURATION_DEBUGGING_PREFIX + method.holder.toSourceString() + ": " + signature); + CONFIGURATION_DEBUGGING_PREFIX + + getReference().holder.toSourceString() + + ": " + + signature); DexString tag = itemFactory.createString("[R8]"); DexType[] args = {itemFactory.stringType, itemFactory.stringType}; DexProto proto = itemFactory.createProto(itemFactory.intType, args); @@ -1110,10 +1105,13 @@ private DexEncodedMethod toMethodThatLogsErrorCfCode(DexItemFactory itemFactory) { checkIfObsolete(); - Signature signature = MethodSignature.fromDexMethod(method); + Signature signature = MethodSignature.fromDexMethod(getReference()); DexString message = itemFactory.createString( - CONFIGURATION_DEBUGGING_PREFIX + method.holder.toSourceString() + ": " + signature); + CONFIGURATION_DEBUGGING_PREFIX + + getReference().holder.toSourceString() + + ": " + + signature); DexString tag = itemFactory.createString("[R8]"); DexType logger = itemFactory.javaUtilLoggingLoggerType; DexMethod getLogger = @@ -1132,7 +1130,7 @@ exceptionType, itemFactory.createProto(itemFactory.voidType, itemFactory.stringType), itemFactory.constructorMethodName); - int locals = method.proto.parameters.size() + 1; + int locals = getReference().proto.parameters.size() + 1; if (!isStaticMember()) { // Consider `this` pointer locals++; @@ -1152,7 +1150,7 @@ .add(new CfThrow()); CfCode code = new CfCode( - method.holder, + getReference().holder, 3, locals, instructionBuilder.build(), @@ -1171,7 +1169,7 @@ public DexEncodedMethod toTypeSubstitutedMethod(DexMethod method, Consumer<Builder> consumer) { checkIfObsolete(); - if (this.method == method) { + if (this.getReference() == method) { return this; } Builder builder = builder(this); @@ -1243,7 +1241,7 @@ public DexEncodedMethod toRenamedHolderMethod(DexType newHolderType, DexItemFactory factory) { DexEncodedMethod.Builder builder = DexEncodedMethod.builder(this); - builder.setMethod(method.withHolder(newHolderType, factory)); + builder.setMethod(getReference().withHolder(newHolderType, factory)); return builder.build(); } @@ -1318,7 +1316,7 @@ public DexEncodedMethod toForwardingMethod( DexClass newHolder, DexDefinitionSupplier definitions) { - DexMethod newMethod = method.withHolder(newHolder, definitions.dexItemFactory()); + DexMethod newMethod = getReference().withHolder(newHolder, definitions.dexItemFactory()); checkIfObsolete(); // Clear the final flag, as this method is now overwritten. Do this before creating the builder @@ -1347,13 +1345,17 @@ .setStaticSource(newMethod) .setStaticTarget( getReference(), - method.getHolderType().isInterface(definitions)), + getReference() + .getHolderType() + .isInterface(definitions)), codeBuilder -> codeBuilder .setNonStaticSource(newMethod) .setSuperTarget( getReference(), - method.getHolderType().isInterface(definitions))) + getReference() + .getHolderType() + .isInterface(definitions))) .build()) .modifyAccessFlags(MethodAccessFlags::setBridge)) .build(); @@ -1435,7 +1437,7 @@ } public MethodPosition getPosition() { - return new MethodPosition(method.asMethodReference()); + return new MethodPosition(getReference().asMethodReference()); } @Override @@ -1456,7 +1458,7 @@ } public static int slowCompare(DexEncodedMethod m1, DexEncodedMethod m2) { - return m1.method.compareTo(m2.method); + return m1.getReference().compareTo(m2.getReference()); } public MethodOptimizationInfo getOptimizationInfo() { @@ -1543,7 +1545,7 @@ private Builder(DexEncodedMethod from, boolean d8R8Synthesized) { // Copy all the mutable state of a DexEncodedMethod here. - method = from.method; + method = from.getReference(); accessFlags = from.accessFlags.copy(); genericSignature = from.getGenericSignature(); annotations = from.annotations();
diff --git a/src/main/java/com/android/tools/r8/graph/DexField.java b/src/main/java/com/android/tools/r8/graph/DexField.java index ef99d01..fd2c110 100644 --- a/src/main/java/com/android/tools/r8/graph/DexField.java +++ b/src/main/java/com/android/tools/r8/graph/DexField.java
@@ -175,7 +175,7 @@ @Override public boolean match(DexEncodedField encodedField) { - return match(encodedField.field); + return match(encodedField.getReference()); } public String qualifiedName() {
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java index 2ce742a..8ba291b 100644 --- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java +++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -64,6 +64,8 @@ public static final String throwableDescriptorString = "Ljava/lang/Throwable;"; public static final String dalvikAnnotationSignatureString = "Ldalvik/annotation/Signature;"; + public static final String recordTagDescriptorString = "Lcom/android/tools/r8/RecordTag;"; + public static final String recordDescriptorString = "Ljava/lang/Record;"; /** Set of types that may be synthesized during compilation. */ private final Set<DexType> possibleCompilerSynthesizedTypes = Sets.newIdentityHashSet(); @@ -215,8 +217,8 @@ public final DexString stringDescriptor = createString("Ljava/lang/String;"); public final DexString stringArrayDescriptor = createString("[Ljava/lang/String;"); public final DexString objectDescriptor = createString("Ljava/lang/Object;"); - public final DexString recordDescriptor = createString("Ljava/lang/Record;"); - public final DexString r8RecordDescriptor = createString("Lcom/android/tools/r8/RecordTag;"); + public final DexString recordDescriptor = createString(recordDescriptorString); + public final DexString recordTagDescriptor = createString(recordTagDescriptorString); public final DexString objectArrayDescriptor = createString("[Ljava/lang/Object;"); public final DexString classDescriptor = createString("Ljava/lang/Class;"); public final DexString classLoaderDescriptor = createString("Ljava/lang/ClassLoader;"); @@ -348,7 +350,7 @@ public final DexType stringArrayType = createStaticallyKnownType(stringArrayDescriptor); public final DexType objectType = createStaticallyKnownType(objectDescriptor); public final DexType recordType = createStaticallyKnownType(recordDescriptor); - public final DexType r8RecordType = createStaticallyKnownType(r8RecordDescriptor); + public final DexType recordTagType = createStaticallyKnownType(recordTagDescriptor); public final DexType objectArrayType = createStaticallyKnownType(objectArrayDescriptor); public final DexType classArrayType = createStaticallyKnownType(classArrayDescriptor); public final DexType enumType = createStaticallyKnownType(enumDescriptor); @@ -631,6 +633,10 @@ public final DexType callSiteType = createStaticallyKnownType("Ljava/lang/invoke/CallSite;"); public final DexType lookupType = createStaticallyKnownType("Ljava/lang/invoke/MethodHandles$Lookup;"); + public final DexType objectMethodsType = + createStaticallyKnownType("Ljava/lang/runtime/ObjectMethods;"); + public final DexType typeDescriptorType = + createStaticallyKnownType("Ljava/lang/invoke/TypeDescriptor;"); public final DexType iteratorType = createStaticallyKnownType("Ljava/util/Iterator;"); public final DexType listIteratorType = createStaticallyKnownType("Ljava/util/ListIterator;"); public final DexType enumerationType = createStaticallyKnownType("Ljava/util/Enumeration;"); @@ -642,6 +648,7 @@ createStaticallyKnownType("Ljava/lang/invoke/StringConcatFactory;"); public final DexType unsafeType = createStaticallyKnownType("Lsun/misc/Unsafe;"); + public final ObjectMethodsMembers objectMethodsMembers = new ObjectMethodsMembers(); public final ServiceLoaderMethods serviceLoaderMethods = new ServiceLoaderMethods(); public final StringConcatFactoryMembers stringConcatFactoryMembers = new StringConcatFactoryMembers(); @@ -1215,6 +1222,21 @@ public final DexMethod toString = createMethod(recordType, createProto(stringType), "toString"); } + public class ObjectMethodsMembers { + public final DexMethod bootstrap = + createMethod( + objectMethodsType, + createProto( + objectType, + lookupType, + stringType, + typeDescriptorType, + classType, + stringType, + createArrayType(1, methodHandleType)), + "bootstrap"); + } + public class ObjectMembers { /**
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java index 8484a94..c96dc4a 100644 --- a/src/main/java/com/android/tools/r8/graph/DexMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -223,7 +223,7 @@ @Override public boolean match(DexEncodedMethod encodedMethod) { - return match(encodedMethod.method); + return match(encodedMethod.getReference()); } public String qualifiedName() {
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java index a4ccb8e..881b0e9 100644 --- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -559,7 +559,8 @@ return null; } DexEncodedField[] fields = staticFields; - Arrays.sort(fields, (a, b) -> a.field.compareToWithNamingLens(b.field, namingLens)); + Arrays.sort( + fields, (a, b) -> a.getReference().compareToWithNamingLens(b.getReference(), namingLens)); int length = 0; List<DexValue> values = new ArrayList<>(fields.length); for (int i = 0; i < fields.length; i++) { @@ -567,7 +568,7 @@ DexValue staticValue = field.getStaticValue(); assert staticValue != null; values.add(staticValue); - if (!staticValue.isDefault(field.field.type)) { + if (!staticValue.isDefault(field.getReference().type)) { length = i + 1; } } @@ -579,7 +580,7 @@ private boolean hasNonDefaultStaticFieldValues() { for (DexEncodedField field : staticFields) { DexValue value = field.getStaticValue(); - if (value != null && !value.isDefault(field.field.type)) { + if (value != null && !value.isDefault(field.getReference().type)) { return true; } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java index 75b592b..a38770a 100644 --- a/src/main/java/com/android/tools/r8/graph/DexType.java +++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -315,6 +315,14 @@ return isDoubleType() || isLongType(); } + public boolean isSynthesizedTypeAllowedDuplication() { + // If we are desugaring Records, then the r8Record type is mapped back to java.lang.Record, and + // java.lang.Record can be duplicated. + // If we are not desugaring Records, then the r8Record type can be duplicated instead. + return descriptor.toString().equals(DexItemFactory.recordDescriptorString) + || descriptor.toString().equals(DexItemFactory.recordTagDescriptorString); + } + public boolean isLegacySynthesizedTypeAllowedDuplication() { return oldSynthesizedName(toSourceString()); }
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignature.java b/src/main/java/com/android/tools/r8/graph/GenericSignature.java index 1dc1f4f..2fa08c8 100644 --- a/src/main/java/com/android/tools/r8/graph/GenericSignature.java +++ b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
@@ -542,6 +542,15 @@ visitor.visitSimpleClass(innerTypeSignature); } } + + public boolean hasTypeVariableArguments() { + for (FieldTypeSignature typeArgument : typeArguments) { + if (typeArgument.isTypeVariableSignature()) { + return true; + } + } + return false; + } } public static class ArrayTypeSignature extends FieldTypeSignature {
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java index 7135cfc..610208f 100644 --- a/src/main/java/com/android/tools/r8/graph/GraphLens.java +++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -13,12 +13,9 @@ import com.android.tools.r8.utils.Action; import com.android.tools.r8.utils.IterableUtils; import com.android.tools.r8.utils.SetUtils; -import com.android.tools.r8.utils.collections.BidirectionalManyToManyRepresentativeMap; import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap; import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap; -import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap; import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneRepresentativeMap; -import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap; import com.android.tools.r8.utils.collections.ProgramMethodSet; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -33,7 +30,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; -import java.util.stream.Collectors; /** * A GraphLens implements a virtual view on top of the graph, used to delay global rewrites until @@ -233,18 +229,16 @@ } } - public static class Builder { + public abstract static class Builder { + + protected final MutableBidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap = + BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap(); + protected final MutableBidirectionalManyToOneRepresentativeMap<DexMethod, DexMethod> methodMap = + BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap(); + protected final Map<DexType, DexType> typeMap = new IdentityHashMap<>(); protected Builder() {} - protected final Map<DexType, DexType> typeMap = new IdentityHashMap<>(); - protected final Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>(); - protected final MutableBidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap = - new BidirectionalManyToOneRepresentativeHashMap<>(); - - protected final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures = - new BidirectionalOneToOneHashMap<>(); - public void map(DexType from, DexType to) { if (from == to) { return; @@ -252,19 +246,11 @@ typeMap.put(from, to); } - public void map(DexMethod from, DexMethod to) { - if (from == to) { - return; - } - methodMap.put(from, to); - } - public void move(DexMethod from, DexMethod to) { if (from == to) { return; } - map(from, to); - originalMethodSignatures.put(to, from); + methodMap.put(from, to); } public void move(DexField from, DexField to) { @@ -274,22 +260,7 @@ fieldMap.put(from, to); } - public GraphLens build(DexItemFactory dexItemFactory) { - return build(dexItemFactory, getIdentityLens()); - } - - public GraphLens build(DexItemFactory dexItemFactory, GraphLens previousLens) { - if (typeMap.isEmpty() && methodMap.isEmpty() && fieldMap.isEmpty()) { - return previousLens; - } - return new NestedGraphLens( - typeMap, - methodMap, - fieldMap, - originalMethodSignatures, - previousLens, - dexItemFactory); - } + public abstract GraphLens build(AppView<?> appView); } /** @@ -334,7 +305,7 @@ DexDefinitionSupplier definitions, GraphLens applied) { assert originalEncodedMethod != DexEncodedMethod.SENTINEL; - DexMethod newMethod = getRenamedMethodSignature(originalEncodedMethod.method, applied); + DexMethod newMethod = getRenamedMethodSignature(originalEncodedMethod.getReference(), applied); // Note that: // * Even if `newMethod` is the same as `originalEncodedMethod.method`, we still need to look it // up, since `originalEncodedMethod` may be obsolete. @@ -602,10 +573,10 @@ Set<DexMethod> originalMethods = Sets.newIdentityHashSet(); for (DexProgramClass clazz : originalApplication.classes()) { for (DexEncodedField field : clazz.fields()) { - originalFields.add(field.field); + originalFields.add(field.getReference()); } for (DexEncodedMethod method : clazz.methods()) { - originalMethods.add(method.method); + originalMethods.add(method.getReference()); } } @@ -631,7 +602,7 @@ // Methods synthesized by D8/R8 may not be mapped. continue; } - DexMethod originalMethod = getOriginalMethodSignature(method.method); + DexMethod originalMethod = getOriginalMethodSignature(method.getReference()); assert originalMethods.contains(originalMethod); } } @@ -959,288 +930,4 @@ return getIdentityLens().isContextFreeForMethods(); } } - - /** - * GraphLens implementation with a parent lens using a simple mapping for type, method and field - * mapping. - * - * <p>Subclasses can override the lookup methods. - * - * <p>For method mapping where invocation type can change just override {@link - * #mapInvocationType(DexMethod, DexMethod, Type)} if the default name mapping applies, and only - * invocation type might need to change. - */ - public static class NestedGraphLens extends NonIdentityGraphLens { - - protected final DexItemFactory dexItemFactory; - - protected final Map<DexType, DexType> typeMap; - protected final Map<DexMethod, DexMethod> methodMap; - protected final BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap; - - // Map that store the original signature of methods that have been affected, for example, by - // vertical class merging. Needed to generate a correct Proguard map in the end. - protected BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> - originalMethodSignatures; - - // Overrides this if the sub type needs to be a nested lens while it doesn't have any mappings - // at all, e.g., publicizer lens that changes invocation type only. - protected boolean isLegitimateToHaveEmptyMappings() { - return false; - } - - public NestedGraphLens( - Map<DexType, DexType> typeMap, - Map<DexMethod, DexMethod> methodMap, - BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap, - BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> originalMethodSignatures, - GraphLens previousLens, - DexItemFactory dexItemFactory) { - super(dexItemFactory, previousLens); - assert !typeMap.isEmpty() - || !methodMap.isEmpty() - || !fieldMap.isEmpty() - || isLegitimateToHaveEmptyMappings(); - this.typeMap = typeMap.isEmpty() ? null : typeMap; - this.methodMap = methodMap; - this.fieldMap = fieldMap; - this.originalMethodSignatures = originalMethodSignatures; - this.dexItemFactory = dexItemFactory; - } - - public static Builder builder() { - return new Builder(); - } - - protected DexType internalGetOriginalType(DexType previous) { - return previous; - } - - protected Iterable<DexType> internalGetOriginalTypes(DexType previous) { - return IterableUtils.singleton(internalGetOriginalType(previous)); - } - - @Override - public DexType getOriginalType(DexType type) { - return getPrevious().getOriginalType(internalGetOriginalType(type)); - } - - @Override - public Iterable<DexType> getOriginalTypes(DexType type) { - return IterableUtils.flatMap(internalGetOriginalTypes(type), getPrevious()::getOriginalTypes); - } - - @Override - public DexField getOriginalFieldSignature(DexField field) { - DexField originalField = fieldMap.getRepresentativeKeyOrDefault(field, field); - return getPrevious().getOriginalFieldSignature(originalField); - } - - @Override - public DexMethod getOriginalMethodSignature(DexMethod method) { - DexMethod originalMethod = internalGetPreviousMethodSignature(method); - return getPrevious().getOriginalMethodSignature(originalMethod); - } - - @Override - public DexField getRenamedFieldSignature(DexField originalField) { - DexField renamedField = getPrevious().getRenamedFieldSignature(originalField); - return internalGetNextFieldSignature(renamedField); - } - - @Override - public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) { - if (this == applied) { - return originalMethod; - } - DexMethod renamedMethod = getPrevious().getRenamedMethodSignature(originalMethod, applied); - return internalGetNextMethodSignature(renamedMethod); - } - - @Override - protected DexType internalDescribeLookupClassType(DexType previous) { - return typeMap != null ? typeMap.getOrDefault(previous, previous) : previous; - } - - @Override - protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) { - if (previous.hasReboundReference()) { - // Rewrite the rebound reference and then "fixup" the non-rebound reference. - DexField rewrittenReboundReference = previous.getRewrittenReboundReference(fieldMap); - DexField rewrittenNonReboundReference = - previous.getReference() == previous.getReboundReference() - ? rewrittenReboundReference - : rewrittenReboundReference.withHolder( - internalDescribeLookupClassType(previous.getReference().getHolderType()), - dexItemFactory); - return FieldLookupResult.builder(this) - .setReboundReference(rewrittenReboundReference) - .setReference(rewrittenNonReboundReference) - .setCastType(previous.getRewrittenCastType(this::internalDescribeLookupClassType)) - .build(); - } else { - // TODO(b/168282032): We should always have the rebound reference, so this should become - // unreachable. - DexField rewrittenReference = previous.getRewrittenReference(fieldMap); - return FieldLookupResult.builder(this) - .setReference(rewrittenReference) - .setCastType(previous.getRewrittenCastType(this::internalDescribeLookupClassType)) - .build(); - } - } - - @Override - public MethodLookupResult internalDescribeLookupMethod( - MethodLookupResult previous, DexMethod context) { - if (previous.hasReboundReference()) { - // TODO(sgjesse): Should we always do interface to virtual mapping? Is it a performance win - // that only subclasses which are known to need it actually do it? - DexMethod rewrittenReboundReference = previous.getRewrittenReboundReference(methodMap); - DexMethod rewrittenReference = - previous.getReference() == previous.getReboundReference() - ? rewrittenReboundReference - : // This assumes that the holder will always be moved in lock-step with the method! - rewrittenReboundReference.withHolder( - internalDescribeLookupClassType(previous.getReference().getHolderType()), - dexItemFactory); - return MethodLookupResult.builder(this) - .setReference(rewrittenReference) - .setReboundReference(rewrittenReboundReference) - .setPrototypeChanges( - internalDescribePrototypeChanges( - previous.getPrototypeChanges(), rewrittenReboundReference)) - .setType( - mapInvocationType( - rewrittenReboundReference, previous.getReference(), previous.getType())) - .build(); - } else { - // TODO(b/168282032): We should always have the rebound reference, so this should become - // unreachable. - DexMethod newMethod = methodMap.get(previous.getReference()); - if (newMethod == null) { - return previous; - } - // TODO(sgjesse): Should we always do interface to virtual mapping? Is it a performance win - // that only subclasses which are known to need it actually do it? - return MethodLookupResult.builder(this) - .setReference(newMethod) - .setPrototypeChanges( - internalDescribePrototypeChanges(previous.getPrototypeChanges(), newMethod)) - .setType(mapInvocationType(newMethod, previous.getReference(), previous.getType())) - .build(); - } - } - - @Override - public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition( - DexMethod method) { - DexMethod previous = internalGetPreviousMethodSignature(method); - RewrittenPrototypeDescription lookup = - getPrevious().lookupPrototypeChangesForMethodDefinition(previous); - return internalDescribePrototypeChanges(lookup, method); - } - - protected RewrittenPrototypeDescription internalDescribePrototypeChanges( - RewrittenPrototypeDescription prototypeChanges, DexMethod method) { - return prototypeChanges; - } - - protected DexField internalGetNextFieldSignature(DexField field) { - return fieldMap.getOrDefault(field, field); - } - - @Override - protected DexMethod internalGetPreviousMethodSignature(DexMethod method) { - return originalMethodSignatures.getRepresentativeValueOrDefault(method, method); - } - - protected DexMethod internalGetNextMethodSignature(DexMethod method) { - return originalMethodSignatures.getRepresentativeKeyOrDefault(method, method); - } - - @Override - public DexMethod lookupGetFieldForMethod(DexField field, DexMethod context) { - return getPrevious().lookupGetFieldForMethod(field, context); - } - - @Override - public DexMethod lookupPutFieldForMethod(DexField field, DexMethod context) { - return getPrevious().lookupPutFieldForMethod(field, context); - } - - /** - * Default invocation type mapping. - * - * <p>This is an identity mapping. If a subclass need invocation type mapping either override - * this method or {@link #lookupMethod(DexMethod, DexMethod, Type)} - */ - protected Type mapInvocationType(DexMethod newMethod, DexMethod originalMethod, Type type) { - return type; - } - - /** - * Standard mapping between interface and virtual invoke type. - * - * <p>Handle methods moved from interface to class or class to interface. - */ - public static Type mapVirtualInterfaceInvocationTypes( - DexDefinitionSupplier definitions, - DexMethod newMethod, - DexMethod originalMethod, - Type type) { - if (type == Type.VIRTUAL || type == Type.INTERFACE) { - // Get the invoke type of the actual definition. - DexClass newTargetClass = definitions.definitionFor(newMethod.getHolderType()); - if (newTargetClass == null) { - return type; - } - DexClass originalTargetClass = definitions.definitionFor(originalMethod.getHolderType()); - if (originalTargetClass != null - && (originalTargetClass.isInterface() ^ (type == Type.INTERFACE))) { - // The invoke was wrong to start with, so we keep it wrong. This is to ensure we get - // the IncompatibleClassChangeError the original invoke would have triggered. - return newTargetClass.accessFlags.isInterface() ? Type.VIRTUAL : Type.INTERFACE; - } - return newTargetClass.accessFlags.isInterface() ? Type.INTERFACE : Type.VIRTUAL; - } - return type; - } - - @Override - public boolean isContextFreeForMethods() { - return getPrevious().isContextFreeForMethods(); - } - - @Override - public boolean verifyIsContextFreeForMethod(DexMethod method) { - assert getPrevious().verifyIsContextFreeForMethod(method); - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - if (typeMap != null) { - for (Map.Entry<DexType, DexType> entry : typeMap.entrySet()) { - builder.append(entry.getKey().toSourceString()).append(" -> "); - builder.append(entry.getValue().toSourceString()).append(System.lineSeparator()); - } - } - for (Map.Entry<DexMethod, DexMethod> entry : methodMap.entrySet()) { - builder.append(entry.getKey().toSourceString()).append(" -> "); - builder.append(entry.getValue().toSourceString()).append(System.lineSeparator()); - } - fieldMap.forEachManyToOneMapping( - (keys, value) -> { - builder.append( - keys.stream() - .map(DexField::toSourceString) - .collect(Collectors.joining("," + System.lineSeparator()))); - builder.append(" -> "); - builder.append(value.toSourceString()).append(System.lineSeparator()); - }); - builder.append(getPrevious().toString()); - return builder.toString(); - } - } }
diff --git a/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java b/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java index 8b5977f..67e7b5b 100644 --- a/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java +++ b/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java
@@ -7,6 +7,7 @@ import com.android.tools.r8.utils.DescriptorUtils; import com.android.tools.r8.utils.InternalOptions; import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.objectweb.asm.Type; @@ -23,9 +24,11 @@ private final ConcurrentHashMap<String, Type> asmObjectTypeCache = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, Type> asmTypeCache = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, DexString> stringCache = new ConcurrentHashMap<>(); + private final Map<String, String> typeDescriptorMap; public JarApplicationReader(InternalOptions options) { this.options = options; + typeDescriptorMap = ApplicationReaderMap.getDescriptorMap(options); } public Type getAsmObjectType(String name) { @@ -55,7 +58,8 @@ public DexType getTypeFromDescriptor(String desc) { assert isValidDescriptor(desc); - return options.itemFactory.createType(getString(desc)); + String actualDesc = typeDescriptorMap.getOrDefault(desc, desc); + return options.itemFactory.createType(getString(actualDesc)); } public DexTypeList getTypeListFromNames(String[] names) {
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java index d8815c7..4def125 100644 --- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java +++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -510,9 +510,9 @@ throw new CompilationError(message, origin); } for (DexEncodedField instanceField : instanceFields) { - if (!recordComponents.contains(instanceField.field)) { + if (!recordComponents.contains(instanceField.getReference())) { throw new CompilationError( - message + " Unmatched field " + instanceField.field + ".", origin); + message + " Unmatched field " + instanceField.getReference() + ".", origin); } } }
diff --git a/src/main/java/com/android/tools/r8/graph/LookupCompletenessHelper.java b/src/main/java/com/android/tools/r8/graph/LookupCompletenessHelper.java index 3c7b2d8..4a99071 100644 --- a/src/main/java/com/android/tools/r8/graph/LookupCompletenessHelper.java +++ b/src/main/java/com/android/tools/r8/graph/LookupCompletenessHelper.java
@@ -34,7 +34,7 @@ if (pinnedMethods == null) { pinnedMethods = Sets.newIdentityHashSet(); } - pinnedMethods.add(method.method); + pinnedMethods.add(method.getReference()); } }
diff --git a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java index 7c38464..17072ef 100644 --- a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java +++ b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
@@ -26,8 +26,8 @@ Set<DexMethod> unique = Sets.newIdentityHashSet(); forEachMethod( method -> { - boolean changed = unique.add(method.method); - assert changed : "Duplicate method `" + method.method.toSourceString() + "`"; + boolean changed = unique.add(method.getReference()); + assert changed : "Duplicate method `" + method.getReference().toSourceString() + "`"; }); return true; }
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollection.java b/src/main/java/com/android/tools/r8/graph/MethodCollection.java index ccf33aa..35e0541 100644 --- a/src/main/java/com/android/tools/r8/graph/MethodCollection.java +++ b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
@@ -137,7 +137,7 @@ public List<DexEncodedMethod> allMethodsSorted() { List<DexEncodedMethod> sorted = new ArrayList<>(size()); forEachMethod(sorted::add); - sorted.sort((a, b) -> a.method.compareTo(b.method)); + sorted.sort((a, b) -> a.getReference().compareTo(b.getReference())); return sorted; } @@ -344,7 +344,7 @@ private boolean verifyCorrectnessOfMethodHolder(DexEncodedMethod method) { assert method.getHolderType() == holder.type : "Expected method `" - + method.method.toSourceString() + + method.getReference().toSourceString() + "` to have holder `" + holder.type.toSourceString() + "`";
diff --git a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java index f3385af..a7d3c45 100644 --- a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java +++ b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
@@ -57,7 +57,7 @@ methodMap.put(existingKey, method); } else { methodMap.remove(existingKey); - methodMap.put(wrap(method.method), method); + methodMap.put(wrap(method.getReference()), method); } } @@ -165,7 +165,7 @@ @Override void addMethod(DexEncodedMethod method) { - Wrapper<DexMethod> key = wrap(method.method); + Wrapper<DexMethod> key = wrap(method.getReference()); DexEncodedMethod old = methodMap.put(key, method); assert old == null; } @@ -229,12 +229,12 @@ forEachMethod( method -> { if (belongsToVirtualPool(method)) { - newMap.put(wrap(method.method), method); + newMap.put(wrap(method.getReference()), method); } }); for (DexEncodedMethod method : methods) { assert belongsToDirectPool(method); - newMap.put(wrap(method.method), method); + newMap.put(wrap(method.getReference()), method); } methodMap = newMap; } @@ -252,12 +252,12 @@ forEachMethod( method -> { if (belongsToDirectPool(method)) { - newMap.put(wrap(method.method), method); + newMap.put(wrap(method.getReference()), method); } }); for (DexEncodedMethod method : methods) { assert belongsToVirtualPool(method); - newMap.put(wrap(method.method), method); + newMap.put(wrap(method.getReference()), method); } methodMap = newMap; } @@ -271,7 +271,7 @@ for (DexEncodedMethod method : initialValues) { DexEncodedMethod newMethod = replacement.apply(method); if (newMethod != method) { - removeMethod(method.method); + removeMethod(method.getReference()); addMethod(newMethod); } } @@ -359,7 +359,7 @@ private boolean verifyVirtualizedMethods(Set<DexEncodedMethod> methods) { for (DexEncodedMethod method : methods) { assert belongsToVirtualPool(method); - assert methodMap.get(wrap(method.method)) == method; + assert methodMap.get(wrap(method.getReference())) == method; } return true; }
diff --git a/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java b/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java new file mode 100644 index 0000000..8eaa46f --- /dev/null +++ b/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
@@ -0,0 +1,320 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.graph; + +import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens; +import com.android.tools.r8.ir.code.Invoke.Type; +import com.android.tools.r8.utils.IterableUtils; +import com.android.tools.r8.utils.collections.BidirectionalManyToManyRepresentativeMap; +import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap; +import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * GraphLens implementation with a parent lens using a simple mapping for type, method and field + * mapping. + * + * <p>Subclasses can override the lookup methods. + * + * <p>For method mapping where invocation type can change just override {@link + * #mapInvocationType(DexMethod, DexMethod, Type)} if the default name mapping applies, and only + * invocation type might need to change. + */ +public class NestedGraphLens extends NonIdentityGraphLens { + + protected static final EmptyBidirectionalOneToOneMap<DexField, DexField> EMPTY_FIELD_MAP = + new EmptyBidirectionalOneToOneMap<>(); + protected static final EmptyBidirectionalOneToOneMap<DexMethod, DexMethod> EMPTY_METHOD_MAP = + new EmptyBidirectionalOneToOneMap<>(); + protected static final Map<DexType, DexType> EMPTY_TYPE_MAP = Collections.emptyMap(); + + protected final BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap; + protected final Map<DexMethod, DexMethod> methodMap; + protected final Map<DexType, DexType> typeMap; + + // Map that stores the new signature of methods that have been affected by class merging, unused + // argument removal, repackaging, synthetic finalization, etc. This is needed to generate a + // correct mapping file in the end. + // + // The difference to `methodMap` is that `methodMap` specifies how invoke-method instructions + // should be rewritten, whereas this map specifies where methods have been moved. In most cases + // the two maps are the same, but in a few cases we move a method m1 to m2 and rewrite invokes to + // m1 to m3. + // + // The static type of this map is a many-to-many map to facilitate both one-to-many mappings and + // many-to-one mappings. Currently, the concrete map is always *either* a one-to-many or a + // many-to-one map, and not a many-to-many map. + // + // One-to-many mappings are generally found when methods are split into two. This could be due to + // the code object being moved elsewhere (e.g., interface desugaring). + // + // Many-to-one mappings are generally found when methods are shared, e.g., due to horizontal class + // merging of synthetic finalization. + protected BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> newMethodSignatures; + + // Overrides this if the sub type needs to be a nested lens while it doesn't have any mappings + // at all, e.g., publicizer lens that changes invocation type only. + protected boolean isLegitimateToHaveEmptyMappings() { + return false; + } + + public NestedGraphLens( + AppView<?> appView, + BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap, + BidirectionalManyToOneRepresentativeMap<DexMethod, DexMethod> methodMap, + Map<DexType, DexType> typeMap) { + this(appView, fieldMap, methodMap.getForwardMap(), typeMap, methodMap); + } + + public NestedGraphLens( + AppView<?> appView, + BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap, + Map<DexMethod, DexMethod> methodMap, + Map<DexType, DexType> typeMap, + BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> newMethodSignatures) { + super(appView); + assert !typeMap.isEmpty() + || !methodMap.isEmpty() + || !fieldMap.isEmpty() + || isLegitimateToHaveEmptyMappings(); + this.fieldMap = fieldMap; + this.methodMap = methodMap; + this.typeMap = typeMap; + this.newMethodSignatures = newMethodSignatures; + } + + protected DexType internalGetOriginalType(DexType previous) { + return previous; + } + + protected Iterable<DexType> internalGetOriginalTypes(DexType previous) { + return IterableUtils.singleton(internalGetOriginalType(previous)); + } + + @Override + public DexType getOriginalType(DexType type) { + return getPrevious().getOriginalType(internalGetOriginalType(type)); + } + + @Override + public Iterable<DexType> getOriginalTypes(DexType type) { + return IterableUtils.flatMap(internalGetOriginalTypes(type), getPrevious()::getOriginalTypes); + } + + @Override + public DexField getOriginalFieldSignature(DexField field) { + DexField originalField = fieldMap.getRepresentativeKeyOrDefault(field, field); + return getPrevious().getOriginalFieldSignature(originalField); + } + + @Override + public DexMethod getOriginalMethodSignature(DexMethod method) { + DexMethod originalMethod = internalGetPreviousMethodSignature(method); + return getPrevious().getOriginalMethodSignature(originalMethod); + } + + @Override + public DexField getRenamedFieldSignature(DexField originalField) { + DexField renamedField = getPrevious().getRenamedFieldSignature(originalField); + return internalGetNextFieldSignature(renamedField); + } + + @Override + public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) { + if (this == applied) { + return originalMethod; + } + DexMethod renamedMethod = getPrevious().getRenamedMethodSignature(originalMethod, applied); + return internalGetNextMethodSignature(renamedMethod); + } + + @Override + protected DexType internalDescribeLookupClassType(DexType previous) { + return typeMap.getOrDefault(previous, previous); + } + + @Override + protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) { + if (previous.hasReboundReference()) { + // Rewrite the rebound reference and then "fixup" the non-rebound reference. + DexField rewrittenReboundReference = previous.getRewrittenReboundReference(fieldMap); + DexField rewrittenNonReboundReference = + previous.getReference() == previous.getReboundReference() + ? rewrittenReboundReference + : rewrittenReboundReference.withHolder( + internalDescribeLookupClassType(previous.getReference().getHolderType()), + dexItemFactory()); + return FieldLookupResult.builder(this) + .setReboundReference(rewrittenReboundReference) + .setReference(rewrittenNonReboundReference) + .setCastType(previous.getRewrittenCastType(this::internalDescribeLookupClassType)) + .build(); + } else { + // TODO(b/168282032): We should always have the rebound reference, so this should become + // unreachable. + DexField rewrittenReference = previous.getRewrittenReference(fieldMap); + return FieldLookupResult.builder(this) + .setReference(rewrittenReference) + .setCastType(previous.getRewrittenCastType(this::internalDescribeLookupClassType)) + .build(); + } + } + + @Override + public MethodLookupResult internalDescribeLookupMethod( + MethodLookupResult previous, DexMethod context) { + if (previous.hasReboundReference()) { + // TODO(sgjesse): Should we always do interface to virtual mapping? Is it a performance win + // that only subclasses which are known to need it actually do it? + DexMethod rewrittenReboundReference = previous.getRewrittenReboundReference(methodMap); + DexMethod rewrittenReference = + previous.getReference() == previous.getReboundReference() + ? rewrittenReboundReference + : // This assumes that the holder will always be moved in lock-step with the method! + rewrittenReboundReference.withHolder( + internalDescribeLookupClassType(previous.getReference().getHolderType()), + dexItemFactory()); + return MethodLookupResult.builder(this) + .setReference(rewrittenReference) + .setReboundReference(rewrittenReboundReference) + .setPrototypeChanges( + internalDescribePrototypeChanges( + previous.getPrototypeChanges(), rewrittenReboundReference)) + .setType( + mapInvocationType( + rewrittenReboundReference, previous.getReference(), previous.getType())) + .build(); + } else { + // TODO(b/168282032): We should always have the rebound reference, so this should become + // unreachable. + DexMethod newMethod = methodMap.get(previous.getReference()); + if (newMethod == null) { + return previous; + } + // TODO(sgjesse): Should we always do interface to virtual mapping? Is it a performance win + // that only subclasses which are known to need it actually do it? + return MethodLookupResult.builder(this) + .setReference(newMethod) + .setPrototypeChanges( + internalDescribePrototypeChanges(previous.getPrototypeChanges(), newMethod)) + .setType(mapInvocationType(newMethod, previous.getReference(), previous.getType())) + .build(); + } + } + + @Override + public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(DexMethod method) { + DexMethod previous = internalGetPreviousMethodSignature(method); + RewrittenPrototypeDescription lookup = + getPrevious().lookupPrototypeChangesForMethodDefinition(previous); + return internalDescribePrototypeChanges(lookup, method); + } + + protected RewrittenPrototypeDescription internalDescribePrototypeChanges( + RewrittenPrototypeDescription prototypeChanges, DexMethod method) { + return prototypeChanges; + } + + protected DexField internalGetNextFieldSignature(DexField field) { + return fieldMap.getOrDefault(field, field); + } + + @Override + protected DexMethod internalGetPreviousMethodSignature(DexMethod method) { + return newMethodSignatures.getRepresentativeKeyOrDefault(method, method); + } + + protected DexMethod internalGetNextMethodSignature(DexMethod method) { + return newMethodSignatures.getRepresentativeValueOrDefault(method, method); + } + + @Override + public DexMethod lookupGetFieldForMethod(DexField field, DexMethod context) { + return getPrevious().lookupGetFieldForMethod(field, context); + } + + @Override + public DexMethod lookupPutFieldForMethod(DexField field, DexMethod context) { + return getPrevious().lookupPutFieldForMethod(field, context); + } + + /** + * Default invocation type mapping. + * + * <p>This is an identity mapping. If a subclass need invocation type mapping either override this + * method or {@link #lookupMethod(DexMethod, DexMethod, Type)} + */ + protected Type mapInvocationType(DexMethod newMethod, DexMethod originalMethod, Type type) { + return type; + } + + /** + * Standard mapping between interface and virtual invoke type. + * + * <p>Handle methods moved from interface to class or class to interface. + */ + public static Type mapVirtualInterfaceInvocationTypes( + DexDefinitionSupplier definitions, DexMethod newMethod, DexMethod originalMethod, Type type) { + if (type == Type.VIRTUAL || type == Type.INTERFACE) { + // Get the invoke type of the actual definition. + DexClass newTargetClass = definitions.definitionFor(newMethod.getHolderType()); + if (newTargetClass == null) { + return type; + } + DexClass originalTargetClass = definitions.definitionFor(originalMethod.getHolderType()); + if (originalTargetClass != null + && (originalTargetClass.isInterface() ^ (type == Type.INTERFACE))) { + // The invoke was wrong to start with, so we keep it wrong. This is to ensure we get + // the IncompatibleClassChangeError the original invoke would have triggered. + return newTargetClass.accessFlags.isInterface() ? Type.VIRTUAL : Type.INTERFACE; + } + return newTargetClass.accessFlags.isInterface() ? Type.INTERFACE : Type.VIRTUAL; + } + return type; + } + + @Override + public boolean isContextFreeForMethods() { + return getPrevious().isContextFreeForMethods(); + } + + @Override + public boolean verifyIsContextFreeForMethod(DexMethod method) { + assert getPrevious().verifyIsContextFreeForMethod(method); + return true; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + typeMap.forEach( + (from, to) -> + builder + .append(from.getTypeName()) + .append(" -> ") + .append(to.getTypeName()) + .append(System.lineSeparator())); + methodMap.forEach( + (from, to) -> + builder + .append(from.toSourceString()) + .append(" -> ") + .append(to.toSourceString()) + .append(System.lineSeparator())); + fieldMap.forEachManyToOneMapping( + (fromSet, to) -> { + builder.append( + fromSet.stream() + .map(DexField::toSourceString) + .collect(Collectors.joining("," + System.lineSeparator()))); + builder.append(" -> "); + builder.append(to.toSourceString()).append(System.lineSeparator()); + }); + builder.append(getPrevious().toString()); + return builder.toString(); + } +}
diff --git a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java index 041033e..e3558a2 100644 --- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java +++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -7,6 +7,7 @@ import com.android.tools.r8.ir.desugar.LambdaDescriptor; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.shaking.InstantiatedObject; +import com.android.tools.r8.utils.BooleanBox; import com.android.tools.r8.utils.Box; import com.android.tools.r8.utils.OptionalBool; import java.util.ArrayList; @@ -60,6 +61,14 @@ return false; } + public boolean isNoSuchMethodErrorResult(DexClass context, AppInfoWithClassHierarchy appInfo) { + return false; + } + + public boolean isIllegalAccessErrorResult(DexClass context, AppInfoWithClassHierarchy appInfo) { + return false; + } + /** Returns non-null if isFailedResolution() is true, otherwise null. */ public FailedResolutionResult asFailedResolution() { return null; @@ -346,7 +355,7 @@ return null; } // 1-3. Search the initial class and its supers in order for a matching instance method. - DexMethod method = getResolvedMethod().method; + DexMethod method = getResolvedMethod().getReference(); DexClassAndMethod target = null; DexClass current = initialType; while (current != null) { @@ -446,7 +455,7 @@ return LookupResult.createResult( methodTargets, lambdaTargets, - incompleteness.computeCollectionState(resolvedMethod.method, appInfo)); + incompleteness.computeCollectionState(resolvedMethod.getReference(), appInfo)); } @Override @@ -626,12 +635,12 @@ private DexClassAndMethod lookupMaximallySpecificDispatchTarget( DexClass dynamicInstance, AppInfoWithClassHierarchy appInfo) { - return appInfo.lookupMaximallySpecificMethod(dynamicInstance, resolvedMethod.method); + return appInfo.lookupMaximallySpecificMethod(dynamicInstance, resolvedMethod.getReference()); } private DexClassAndMethod lookupMaximallySpecificDispatchTarget( LambdaDescriptor lambdaDescriptor, AppInfoWithClassHierarchy appInfo) { - return appInfo.lookupMaximallySpecificMethod(lambdaDescriptor, resolvedMethod.method); + return appInfo.lookupMaximallySpecificMethod(lambdaDescriptor, resolvedMethod.getReference()); } /** @@ -642,7 +651,7 @@ */ private static DexEncodedMethod lookupOverrideCandidate( DexEncodedMethod method, DexClass clazz) { - DexEncodedMethod candidate = clazz.lookupVirtualMethod(method.method); + DexEncodedMethod candidate = clazz.lookupVirtualMethod(method.getReference()); assert candidate == null || !candidate.isPrivateMethod(); if (candidate != null) { return isOverriding(method, candidate) ? candidate : DexEncodedMethod.SENTINEL; @@ -659,7 +668,7 @@ if (clazz == null) { return resolvedMethod; } - DexEncodedMethod otherOverride = clazz.lookupVirtualMethod(resolvedMethod.method); + DexEncodedMethod otherOverride = clazz.lookupVirtualMethod(resolvedMethod.getReference()); if (otherOverride != null && isOverriding(resolvedMethod, otherOverride) && (otherOverride.accessFlags.isPublic() || otherOverride.accessFlags.isProtected())) { @@ -680,7 +689,7 @@ */ public static boolean isOverriding( DexEncodedMethod resolvedMethod, DexEncodedMethod candidate) { - assert resolvedMethod.method.match(candidate.method); + assert resolvedMethod.getReference().match(candidate.getReference()); assert !candidate.isPrivateMethod(); if (resolvedMethod.accessFlags.isPublic() || resolvedMethod.accessFlags.isProtected()) { return true; @@ -814,6 +823,10 @@ public boolean isVirtualTarget() { return false; } + + public boolean hasMethodsCausingError() { + return false; + } } public static class ClassNotFoundResult extends FailedResolutionResult { @@ -824,7 +837,7 @@ } } - abstract static class FailedResolutionWithCausingMethods extends FailedResolutionResult { + public abstract static class FailedResolutionWithCausingMethods extends FailedResolutionResult { private final Collection<DexEncodedMethod> methodsCausingError; @@ -836,6 +849,11 @@ public void forEachFailureDependency(Consumer<DexEncodedMethod> methodCausingFailureConsumer) { this.methodsCausingError.forEach(methodCausingFailureConsumer); } + + @Override + public boolean hasMethodsCausingError() { + return methodsCausingError.size() > 0; + } } public static class IncompatibleClassResult extends FailedResolutionWithCausingMethods { @@ -861,13 +879,70 @@ public static class NoSuchMethodResult extends FailedResolutionResult { static final NoSuchMethodResult INSTANCE = new NoSuchMethodResult(); + + @Override + public boolean isNoSuchMethodErrorResult(DexClass context, AppInfoWithClassHierarchy appInfo) { + return true; + } } - public static class IllegalAccessOrNoSuchMethodResult extends FailedResolutionWithCausingMethods { + static class IllegalAccessOrNoSuchMethodResult extends FailedResolutionWithCausingMethods { - public IllegalAccessOrNoSuchMethodResult(DexEncodedMethod methodCausingError) { - super(Collections.singletonList(methodCausingError)); + private final DexClass initialResolutionHolder; + + public IllegalAccessOrNoSuchMethodResult( + DexClass initialResolutionHolder, Collection<DexEncodedMethod> methodsCausingError) { + super(methodsCausingError); + this.initialResolutionHolder = initialResolutionHolder; + } + + public IllegalAccessOrNoSuchMethodResult( + DexClass initialResolutionHolder, DexEncodedMethod methodCausingError) { + this(initialResolutionHolder, Collections.singletonList(methodCausingError)); assert methodCausingError != null; } + + @Override + public boolean isIllegalAccessErrorResult(DexClass context, AppInfoWithClassHierarchy appInfo) { + if (!hasMethodsCausingError()) { + return false; + } + BooleanBox seenNoAccess = new BooleanBox(false); + forEachFailureDependency( + method -> { + DexClassAndMethod classAndMethod = + DexClassAndMethod.create(appInfo.definitionFor(method.getHolderType()), method); + seenNoAccess.or( + AccessControl.isMemberAccessible( + classAndMethod, initialResolutionHolder, context, appInfo) + .isFalse()); + }); + return seenNoAccess.get(); + } + + @Override + public boolean isNoSuchMethodErrorResult(DexClass context, AppInfoWithClassHierarchy appInfo) { + if (!hasMethodsCausingError()) { + return true; + } + if (isIllegalAccessErrorResult(context, appInfo)) { + return false; + } + // At this point we know we have methods causing errors but we have access to them. To be + // certain that this is the case where we have nest access but we are invoking a method with + // an incorrect symbolic reference, we directly test for it by having an assert. + assert verifyInvalidSymbolicReference(); + return true; + } + + private boolean verifyInvalidSymbolicReference() { + BooleanBox invalidSymbolicReference = new BooleanBox(true); + forEachFailureDependency( + method -> { + invalidSymbolicReference.and( + method.getHolderType() != initialResolutionHolder.getType()); + }); + return invalidSymbolicReference.get(); + } } }
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java index add54d6..c016016 100644 --- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java +++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
@@ -133,8 +133,8 @@ private final DexType oldType; private final DexType newType; - static RewrittenTypeInfo toVoid(DexType oldReturnType, AppView<?> appView) { - return new RewrittenTypeInfo(oldReturnType, appView.dexItemFactory().voidType); + static RewrittenTypeInfo toVoid(DexType oldReturnType, DexItemFactory dexItemFactory) { + return new RewrittenTypeInfo(oldReturnType, dexItemFactory.voidType); } public RewrittenTypeInfo(DexType oldType, DexType newType) { @@ -150,8 +150,8 @@ return oldType; } - boolean hasBeenChangedToReturnVoid(AppView<?> appView) { - return newType == appView.dexItemFactory().voidType; + boolean hasBeenChangedToReturnVoid(DexItemFactory dexItemFactory) { + return newType == dexItemFactory.voidType; } @Override @@ -252,7 +252,7 @@ // Currently not allowed to remove the receiver of an instance method. This would involve // changing invoke-direct/invoke-virtual into invoke-static. assert encodedMethod.isStatic() || !getArgumentInfo(0).isRemovedArgumentInfo(); - DexType[] params = encodedMethod.method.proto.parameters.values; + DexType[] params = encodedMethod.getReference().proto.parameters.values; if (isEmpty()) { return params; } @@ -367,7 +367,9 @@ ArgumentInfoCollection removedArgumentsInfo) { DexType returnType = method.proto.returnType; RewrittenTypeInfo returnInfo = - returnType.isAlwaysNull(appView) ? RewrittenTypeInfo.toVoid(returnType, appView) : null; + returnType.isAlwaysNull(appView) + ? RewrittenTypeInfo.toVoid(returnType, appView.dexItemFactory()) + : null; return create(Collections.emptyList(), returnInfo, removedArgumentsInfo); } @@ -394,8 +396,9 @@ return extraParameters.size(); } - public boolean hasBeenChangedToReturnVoid(AppView<?> appView) { - return rewrittenReturnInfo != null && rewrittenReturnInfo.hasBeenChangedToReturnVoid(appView); + public boolean hasBeenChangedToReturnVoid(DexItemFactory dexItemFactory) { + return rewrittenReturnInfo != null + && rewrittenReturnInfo.hasBeenChangedToReturnVoid(dexItemFactory); } public ArgumentInfoCollection getArgumentInfoCollection() { @@ -433,23 +436,23 @@ public DexProto rewriteProto(DexEncodedMethod encodedMethod, DexItemFactory dexItemFactory) { if (isEmpty()) { - return encodedMethod.method.proto; + return encodedMethod.getReference().proto; } DexType newReturnType = rewrittenReturnInfo != null ? rewrittenReturnInfo.newType - : encodedMethod.method.proto.returnType; + : encodedMethod.getReference().proto.returnType; DexType[] newParameters = argumentInfoCollection.rewriteParameters(encodedMethod); return dexItemFactory.createProto(newReturnType, newParameters); } public RewrittenPrototypeDescription withConstantReturn( - DexType oldReturnType, AppView<?> appView) { + DexType oldReturnType, DexItemFactory dexItemFactory) { assert rewrittenReturnInfo == null; - return !hasBeenChangedToReturnVoid(appView) + return !hasBeenChangedToReturnVoid(dexItemFactory) ? new RewrittenPrototypeDescription( extraParameters, - RewrittenTypeInfo.toVoid(oldReturnType, appView), + RewrittenTypeInfo.toVoid(oldReturnType, dexItemFactory), argumentInfoCollection) : this; }
diff --git a/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java b/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java index 27f3251..5bbc1ee 100644 --- a/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java +++ b/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java
@@ -43,7 +43,7 @@ } private DexEncodedField recordFieldChange(DexEncodedField from, DexEncodedField to) { - recordFieldChange(from.field, to.field); + recordFieldChange(from.getReference(), to.getReference()); return to; } @@ -77,7 +77,7 @@ /** Callback to allow custom handling when an encoded method changes. */ public DexEncodedMethod recordMethodChange(DexEncodedMethod from, DexEncodedMethod to) { - recordMethodChange(from.method, to.method); + recordMethodChange(from.getReference(), to.getReference()); return to; }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java index 0e7d164..a47acd6 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -63,7 +63,6 @@ private final DexItemFactory dexItemFactory; private final ClassInitializerSynthesizedCode classInitializerSynthesizedCode; private final HorizontalClassMergerGraphLens.Builder lensBuilder; - private final HorizontallyMergedClasses.Builder mergedClassesBuilder; private final ClassMethodsBuilder classMethodsBuilder = new ClassMethodsBuilder(); private final Reference2IntMap<DexType> classIdentifiers = new Reference2IntOpenHashMap<>(); @@ -75,14 +74,12 @@ private ClassMerger( AppView<AppInfoWithLiveness> appView, HorizontalClassMergerGraphLens.Builder lensBuilder, - HorizontallyMergedClasses.Builder mergedClassesBuilder, MergeGroup group, Collection<VirtualMethodMerger> virtualMethodMergers, Collection<ConstructorMerger> constructorMergers, ClassInitializerSynthesizedCode classInitializerSynthesizedCode) { this.appView = appView; this.lensBuilder = lensBuilder; - this.mergedClassesBuilder = mergedClassesBuilder; this.group = group; this.virtualMethodMergers = virtualMethodMergers; this.constructorMergers = constructorMergers; @@ -95,10 +92,6 @@ buildClassIdentifierMap(); } - MergeGroup getGroup() { - return group; - } - void buildClassIdentifierMap() { classIdentifiers.put(group.getTarget().getType(), 0); group.forEachSource(clazz -> classIdentifiers.put(clazz.getType(), classIdentifiers.size())); @@ -174,7 +167,7 @@ DexMethod renameDirectMethod(ProgramMethod method) { assert method.getDefinition().belongsToDirectPool(); return dexItemFactory.createFreshMethodName( - method.getDefinition().method.name.toSourceString(), + method.getDefinition().getReference().name.toSourceString(), method.getHolderType(), method.getDefinition().getProto(), group.getTarget().getType(), @@ -279,8 +272,6 @@ mergeStaticFields(); mergeInstanceFields(); - - mergedClassesBuilder.addMergeGroup(group); } public static class Builder { @@ -351,7 +342,6 @@ } public ClassMerger build( - HorizontallyMergedClasses.Builder mergedClassesBuilder, HorizontalClassMergerGraphLens.Builder lensBuilder) { setup(); List<VirtualMethodMerger> virtualMethodMergers = @@ -377,7 +367,6 @@ return new ClassMerger( appView, lensBuilder, - mergedClassesBuilder, group, virtualMethodMergers, constructorMergers,
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java index 05e91a4..7085879 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -40,8 +40,8 @@ import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier; import com.android.tools.r8.shaking.KeepInfoCollection; import com.android.tools.r8.shaking.RuntimeTypeCheckInfo; +import com.android.tools.r8.utils.Timing; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -56,14 +56,13 @@ assert appView.options().enableInlining; } - public HorizontalClassMergerResult run( - RuntimeTypeCheckInfo runtimeTypeCheckInfo) { + public HorizontalClassMergerResult run(RuntimeTypeCheckInfo runtimeTypeCheckInfo, Timing timing) { MergeGroup initialGroup = new MergeGroup(appView.appInfo().classesWithDeterministicOrder()); // Run the policies on all program classes to produce a final grouping. List<Policy> policies = getPolicies(runtimeTypeCheckInfo); Collection<MergeGroup> groups = - new SimplePolicyExecutor().run(Collections.singletonList(initialGroup), policies); + new PolicyExecutor().run(Collections.singletonList(initialGroup), policies, timing); // If there are no groups, then end horizontal class merging. if (groups.isEmpty()) { @@ -71,25 +70,18 @@ return null; } - HorizontallyMergedClasses.Builder mergedClassesBuilder = - new HorizontallyMergedClasses.Builder(); HorizontalClassMergerGraphLens.Builder lensBuilder = new HorizontalClassMergerGraphLens.Builder(); - // Set up a class merger for each group. - List<ClassMerger> classMergers = - initializeClassMergers(mergedClassesBuilder, lensBuilder, groups); - Iterable<DexProgramClass> allMergeClasses = - Iterables.concat( - Iterables.transform(classMergers, classMerger -> classMerger.getGroup().getClasses())); - // Merge the classes. + List<ClassMerger> classMergers = initializeClassMergers(lensBuilder, groups); SyntheticArgumentClass syntheticArgumentClass = - new SyntheticArgumentClass.Builder(appView).build(allMergeClasses); + new SyntheticArgumentClass.Builder(appView).build(groups); applyClassMergers(classMergers, syntheticArgumentClass); // Generate the graph lens. - HorizontallyMergedClasses mergedClasses = mergedClassesBuilder.build(); + HorizontallyMergedClasses mergedClasses = + HorizontallyMergedClasses.builder().addMergeGroups(groups).build(); appView.setHorizontallyMergedClasses(mergedClasses); HorizontalClassMergerGraphLens lens = createLens(mergedClasses, lensBuilder, syntheticArgumentClass); @@ -163,7 +155,6 @@ * be merged and how the merging should be performed. */ private List<ClassMerger> initializeClassMergers( - HorizontallyMergedClasses.Builder mergedClassesBuilder, HorizontalClassMergerGraphLens.Builder lensBuilder, Collection<MergeGroup> groups) { List<ClassMerger> classMergers = new ArrayList<>(); @@ -171,8 +162,7 @@ // TODO(b/166577694): Replace Collection<DexProgramClass> with MergeGroup for (MergeGroup group : groups) { assert !group.isEmpty(); - ClassMerger merger = - new ClassMerger.Builder(appView, group).build(mergedClassesBuilder, lensBuilder); + ClassMerger merger = new ClassMerger.Builder(appView, group).build(lensBuilder); classMergers.add(merger); }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java index f5fdd6f..4358dc8 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
@@ -8,14 +8,12 @@ import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexType; -import com.android.tools.r8.graph.GraphLens.NestedGraphLens; +import com.android.tools.r8.graph.NestedGraphLens; import com.android.tools.r8.ir.conversion.ExtraParameter; import com.android.tools.r8.utils.IterableUtils; import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap; import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap; import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap; -import com.android.tools.r8.utils.collections.BidirectionalOneToManyRepresentativeHashMap; -import com.android.tools.r8.utils.collections.BidirectionalOneToManyRepresentativeMap; import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneRepresentativeMap; import com.google.common.collect.Iterables; import com.google.common.collect.Streams; @@ -36,14 +34,8 @@ Map<DexMethod, List<ExtraParameter>> methodExtraParameters, BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap, Map<DexMethod, DexMethod> methodMap, - BidirectionalOneToManyRepresentativeMap<DexMethod, DexMethod> originalMethodSignatures) { - super( - mergedClasses.getForwardMap(), - methodMap, - fieldMap, - originalMethodSignatures, - appView.graphLens(), - appView.dexItemFactory()); + BidirectionalManyToOneRepresentativeMap<DexMethod, DexMethod> newMethodSignatures) { + super(appView, fieldMap, methodMap, mergedClasses.getForwardMap(), newMethodSignatures); this.methodExtraParameters = methodExtraParameters; this.mergedClasses = mergedClasses; } @@ -91,32 +83,33 @@ public static class Builder { private final MutableBidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap = - new BidirectionalManyToOneRepresentativeHashMap<>(); + BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap(); private final BidirectionalManyToOneHashMap<DexMethod, DexMethod> methodMap = - new BidirectionalManyToOneHashMap<>(); - private final BidirectionalOneToManyRepresentativeHashMap<DexMethod, DexMethod> - originalMethodSignatures = new BidirectionalOneToManyRepresentativeHashMap<>(); + BidirectionalManyToOneHashMap.newIdentityHashMap(); + private final BidirectionalManyToOneRepresentativeHashMap<DexMethod, DexMethod> + newMethodSignatures = BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap(); private final Map<DexMethod, List<ExtraParameter>> methodExtraParameters = new IdentityHashMap<>(); private final BidirectionalManyToOneHashMap<DexMethod, DexMethod> pendingMethodMapUpdates = - new BidirectionalManyToOneHashMap<>(); - private final BidirectionalOneToManyRepresentativeHashMap<DexMethod, DexMethod> - pendingOriginalMethodSignatureUpdates = new BidirectionalOneToManyRepresentativeHashMap<>(); + BidirectionalManyToOneHashMap.newIdentityHashMap(); + private final BidirectionalManyToOneRepresentativeHashMap<DexMethod, DexMethod> + pendingNewMethodSignatureUpdates = + BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap(); Builder() {} HorizontalClassMergerGraphLens build( AppView<?> appView, HorizontallyMergedClasses mergedClasses) { assert pendingMethodMapUpdates.isEmpty(); - assert pendingOriginalMethodSignatureUpdates.isEmpty(); + assert pendingNewMethodSignatureUpdates.isEmpty(); return new HorizontalClassMergerGraphLens( appView, mergedClasses, methodExtraParameters, fieldMap, methodMap.getForwardMap(), - originalMethodSignatures); + newMethodSignatures); } void recordNewFieldSignature(DexField oldFieldSignature, DexField newFieldSignature) { @@ -161,7 +154,7 @@ } void recordNewMethodSignature(DexMethod oldMethodSignature, DexMethod newMethodSignature) { - originalMethodSignatures.put(newMethodSignature, oldMethodSignature); + newMethodSignatures.put(oldMethodSignature, newMethodSignature); } void fixupMethod(DexMethod oldMethodSignature, DexMethod newMethodSignature) { @@ -182,12 +175,12 @@ private void fixupOriginalMethodSignatures( DexMethod oldMethodSignature, DexMethod newMethodSignature) { - Set<DexMethod> oldMethodSignatures = originalMethodSignatures.getValues(oldMethodSignature); + Set<DexMethod> oldMethodSignatures = newMethodSignatures.getKeys(oldMethodSignature); if (oldMethodSignatures.isEmpty()) { - pendingOriginalMethodSignatureUpdates.put(newMethodSignature, oldMethodSignature); + pendingNewMethodSignatureUpdates.put(oldMethodSignature, newMethodSignature); } else { for (DexMethod originalMethodSignature : oldMethodSignatures) { - pendingOriginalMethodSignatureUpdates.put(newMethodSignature, originalMethodSignature); + pendingNewMethodSignatureUpdates.put(originalMethodSignature, newMethodSignature); } } } @@ -199,9 +192,9 @@ pendingMethodMapUpdates.clear(); // Commit pending original method signatures updates. - originalMethodSignatures.removeAll(pendingOriginalMethodSignatureUpdates.keySet()); - pendingOriginalMethodSignatureUpdates.forEachOneToManyMapping(originalMethodSignatures::put); - pendingOriginalMethodSignatureUpdates.clear(); + newMethodSignatures.removeAll(pendingNewMethodSignatureUpdates.keySet()); + pendingNewMethodSignatureUpdates.forEachManyToOneMapping(newMethodSignatures::put); + pendingNewMethodSignatureUpdates.clear(); } /**
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontallyMergedClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontallyMergedClasses.java index 93f9d3f..927e629 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontallyMergedClasses.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontallyMergedClasses.java
@@ -24,6 +24,10 @@ this.mergedClasses = mergedClasses; } + static Builder builder() { + return new Builder(); + } + public static HorizontallyMergedClasses empty() { return new HorizontallyMergedClasses(new EmptyBidirectionalOneToOneMap<>()); } @@ -79,15 +83,21 @@ } public static class Builder { - private final MutableBidirectionalManyToOneMap<DexType, DexType> mergedClasses = - new BidirectionalManyToOneHashMap<>(); - public HorizontallyMergedClasses build() { - return new HorizontallyMergedClasses(mergedClasses); + private final MutableBidirectionalManyToOneMap<DexType, DexType> mergedClasses = + BidirectionalManyToOneHashMap.newIdentityHashMap(); + + void addMergeGroup(MergeGroup group) { + group.forEachSource(clazz -> mergedClasses.put(clazz.getType(), group.getTarget().getType())); } - public void addMergeGroup(MergeGroup group) { - group.forEachSource(clazz -> mergedClasses.put(clazz.getType(), group.getTarget().getType())); + Builder addMergeGroups(Iterable<MergeGroup> groups) { + groups.forEach(this::addMergeGroup); + return this; + } + + HorizontallyMergedClasses build() { + return new HorizontallyMergedClasses(mergedClasses); } } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/Policy.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/Policy.java index 4642229..b984ed5 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/Policy.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/Policy.java
@@ -14,6 +14,8 @@ public void clear() {} + public abstract String getName(); + public boolean shouldSkipPolicy() { return false; }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyExecutor.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyExecutor.java index b94adf8..33b6f7f 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyExecutor.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyExecutor.java
@@ -4,15 +4,88 @@ package com.android.tools.r8.horizontalclassmerging; +import com.android.tools.r8.utils.IterableUtils; +import com.android.tools.r8.utils.Timing; import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; -public abstract class PolicyExecutor { +/** + * This is a simple policy executor that ensures regular sequential execution of policies. It should + * primarily be readable and correct. The SimplePolicyExecutor should be a reference implementation, + * against which more efficient policy executors can be compared. + */ +public class PolicyExecutor { + + // TODO(b/165506334): if performing mutable operation ensure that linked lists are used + private void applySingleClassPolicy(SingleClassPolicy policy, LinkedList<MergeGroup> groups) { + Iterator<MergeGroup> i = groups.iterator(); + while (i.hasNext()) { + MergeGroup group = i.next(); + int previousNumberOfClasses = group.size(); + group.removeIf(clazz -> !policy.canMerge(clazz)); + policy.numberOfRemovedClasses += previousNumberOfClasses - group.size(); + if (group.size() < 2) { + i.remove(); + } + } + } + + private LinkedList<MergeGroup> applyMultiClassPolicy( + MultiClassPolicy policy, LinkedList<MergeGroup> groups) { + // For each group apply the multi class policy and add all the new groups together. + LinkedList<MergeGroup> newGroups = new LinkedList<>(); + groups.forEach( + group -> { + int previousNumberOfClasses = group.size(); + Collection<MergeGroup> policyGroups = policy.apply(group); + policyGroups.forEach(newGroup -> newGroup.applyMetadataFrom(group)); + policy.numberOfRemovedClasses += + previousNumberOfClasses - IterableUtils.sumInt(policyGroups, MergeGroup::size); + newGroups.addAll(policyGroups); + }); + return newGroups; + } /** * Given an initial collection of class groups which can potentially be merged, run all of the * policies registered to this policy executor on the class groups yielding a new collection of * class groups. */ - public abstract Collection<MergeGroup> run( - Collection<MergeGroup> classes, Collection<Policy> policies); + public Collection<MergeGroup> run( + Collection<MergeGroup> inputGroups, Collection<Policy> policies, Timing timing) { + LinkedList<MergeGroup> linkedGroups; + + if (inputGroups instanceof LinkedList) { + linkedGroups = (LinkedList<MergeGroup>) inputGroups; + } else { + linkedGroups = new LinkedList<>(inputGroups); + } + + for (Policy policy : policies) { + if (policy.shouldSkipPolicy()) { + continue; + } + + timing.begin(policy.getName()); + if (policy instanceof SingleClassPolicy) { + applySingleClassPolicy((SingleClassPolicy) policy, linkedGroups); + } else { + assert policy instanceof MultiClassPolicy; + linkedGroups = applyMultiClassPolicy((MultiClassPolicy) policy, linkedGroups); + } + timing.end(); + + policy.clear(); + + if (linkedGroups.isEmpty()) { + break; + } + + // Any policy should not return any trivial groups. + assert linkedGroups.stream().allMatch(group -> group.size() >= 2); + } + + return linkedGroups; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java deleted file mode 100644 index 3b96a76..0000000 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java +++ /dev/null
@@ -1,85 +0,0 @@ -// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -package com.android.tools.r8.horizontalclassmerging; - -import com.android.tools.r8.utils.IterableUtils; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; - -/** - * This is a simple policy executor that ensures regular sequential execution of policies. It should - * primarily be readable and correct. The SimplePolicyExecutor should be a reference implementation, - * against which more efficient policy executors can be compared. - */ -public class SimplePolicyExecutor extends PolicyExecutor { - - // TODO(b/165506334): if performing mutable operation ensure that linked lists are used - private LinkedList<MergeGroup> applySingleClassPolicy( - SingleClassPolicy policy, LinkedList<MergeGroup> groups) { - Iterator<MergeGroup> i = groups.iterator(); - while (i.hasNext()) { - MergeGroup group = i.next(); - int previousNumberOfClasses = group.size(); - group.removeIf(clazz -> !policy.canMerge(clazz)); - policy.numberOfRemovedClasses += previousNumberOfClasses - group.size(); - if (group.size() < 2) { - i.remove(); - } - } - return groups; - } - - private LinkedList<MergeGroup> applyMultiClassPolicy( - MultiClassPolicy policy, LinkedList<MergeGroup> groups) { - // For each group apply the multi class policy and add all the new groups together. - LinkedList<MergeGroup> newGroups = new LinkedList<>(); - groups.forEach( - group -> { - int previousNumberOfClasses = group.size(); - Collection<MergeGroup> policyGroups = policy.apply(group); - policyGroups.forEach(newGroup -> newGroup.applyMetadataFrom(group)); - policy.numberOfRemovedClasses += - previousNumberOfClasses - IterableUtils.sumInt(policyGroups, MergeGroup::size); - newGroups.addAll(policyGroups); - }); - return newGroups; - } - - @Override - public Collection<MergeGroup> run( - Collection<MergeGroup> inputGroups, Collection<Policy> policies) { - LinkedList<MergeGroup> linkedGroups; - - if (inputGroups instanceof LinkedList) { - linkedGroups = (LinkedList<MergeGroup>) inputGroups; - } else { - linkedGroups = new LinkedList<>(inputGroups); - } - - for (Policy policy : policies) { - if (policy.shouldSkipPolicy()) { - continue; - } - - if (policy instanceof SingleClassPolicy) { - linkedGroups = applySingleClassPolicy((SingleClassPolicy) policy, linkedGroups); - } else if (policy instanceof MultiClassPolicy) { - linkedGroups = applyMultiClassPolicy((MultiClassPolicy) policy, linkedGroups); - } - - policy.clear(); - - if (linkedGroups.isEmpty()) { - break; - } - - // Any policy should not return any trivial groups. - assert linkedGroups.stream().allMatch(group -> group.size() >= 2); - } - - return linkedGroups; - } -}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/SyntheticArgumentClass.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/SyntheticArgumentClass.java index ca0b752..c8cc19e 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/SyntheticArgumentClass.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/SyntheticArgumentClass.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind; import java.util.ArrayList; +import java.util.Collection; import java.util.List; /** @@ -55,9 +56,8 @@ .createFixedClass(syntheticKind, context, appView.dexItemFactory(), builder -> {}); } - public SyntheticArgumentClass build(Iterable<DexProgramClass> mergeClasses) { - // Find a fresh name in an existing package. - DexProgramClass context = mergeClasses.iterator().next(); + public SyntheticArgumentClass build(Collection<MergeGroup> mergeGroups) { + DexProgramClass context = getDeterministicContext(mergeGroups); List<DexType> syntheticArgumentTypes = new ArrayList<>(); syntheticArgumentTypes.add( synthesizeClass(context, SyntheticKind.HORIZONTAL_INIT_TYPE_ARGUMENT_1).getType()); @@ -67,5 +67,12 @@ synthesizeClass(context, SyntheticKind.HORIZONTAL_INIT_TYPE_ARGUMENT_3).getType()); return new SyntheticArgumentClass(syntheticArgumentTypes); } + + private static DexProgramClass getDeterministicContext(Collection<MergeGroup> mergeGroups) { + // Relies on the determinism of the merge groups. + MergeGroup mergeGroup = mergeGroups.iterator().next(); + assert mergeGroup.hasTarget(); + return mergeGroup.getTarget(); + } } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java index e8130ed..c144128 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -112,7 +112,7 @@ flags.setPrivate(); classMethodsBuilder.addDirectMethod(encodedMethod); - return encodedMethod.method; + return encodedMethod.getReference(); } private MethodAccessFlags getAccessFlags() {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/AllInstantiatedOrUninstantiated.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/AllInstantiatedOrUninstantiated.java index 75d61d9..38150db 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/AllInstantiatedOrUninstantiated.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/AllInstantiatedOrUninstantiated.java
@@ -21,4 +21,9 @@ public Boolean getMergeKey(DexProgramClass clazz) { return appView.appInfo().isInstantiatedDirectlyOrIndirectly(clazz); } + + @Override + public String getName() { + return "AllInstantiatedOrUninstantiated"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckAbstractClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckAbstractClasses.java index 6e5c711..e78b196 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckAbstractClasses.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckAbstractClasses.java
@@ -25,6 +25,11 @@ } @Override + public String getName() { + return "CheckAbstractClasses"; + } + + @Override public boolean shouldSkipPolicy() { // We can just make the target class non-abstract if one of the classes in the group // is non-abstract.
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/DontInlinePolicy.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/DontInlinePolicy.java index f7d121a..e6e67e0 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/DontInlinePolicy.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/DontInlinePolicy.java
@@ -12,16 +12,14 @@ import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.shaking.AppInfoWithLiveness; -import com.android.tools.r8.shaking.MainDexInfo; import com.google.common.collect.Iterables; public class DontInlinePolicy extends SingleClassPolicy { + private final AppView<AppInfoWithLiveness> appView; - private final MainDexInfo mainDexInfo; public DontInlinePolicy(AppView<AppInfoWithLiveness> appView) { this.appView = appView; - this.mainDexInfo = appView.appInfo().getMainDexInfo(); } private boolean disallowInlining(ProgramMethod method) { @@ -53,4 +51,9 @@ program.directProgramMethods(), method -> method.getDefinition().isInstanceInitializer() && disallowInlining(method)); } + + @Override + public String getName() { + return "DontInlinePolicy"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/DontMergeSynchronizedClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/DontMergeSynchronizedClasses.java index 4372869..e1cb9a7 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/DontMergeSynchronizedClasses.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/DontMergeSynchronizedClasses.java
@@ -56,4 +56,9 @@ return synchronizedGroups; } + + @Override + public String getName() { + return "DontMergeSynchronizedClasses"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitGroups.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitGroups.java index 33de8f3..80e1292 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitGroups.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitGroups.java
@@ -52,4 +52,9 @@ newGroups.add(newGroup); return newGroup; } + + @Override + public String getName() { + return "LimitGroups"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/MinimizeFieldCasts.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/MinimizeFieldCasts.java index 73e0786..1ef2f6a 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/MinimizeFieldCasts.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/MinimizeFieldCasts.java
@@ -70,4 +70,9 @@ } return fieldTypes; } + + @Override + public String getName() { + return "MinimizeFieldCasts"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoAnnotationClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoAnnotationClasses.java index 1effb8b..9943010 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoAnnotationClasses.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoAnnotationClasses.java
@@ -12,4 +12,9 @@ public boolean canMerge(DexProgramClass program) { return !program.isAnnotation(); } + + @Override + public String getName() { + return "NoAnnotationClasses"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassAnnotationCollisions.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassAnnotationCollisions.java index 9d3d730..1a96901 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassAnnotationCollisions.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassAnnotationCollisions.java
@@ -41,4 +41,9 @@ } return removeTrivialGroups(newGroups); } + + @Override + public String getName() { + return "NoClassAnnotationCollisions"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerWithObservableSideEffects.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerWithObservableSideEffects.java index f10d78c..b156a2e 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerWithObservableSideEffects.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerWithObservableSideEffects.java
@@ -28,4 +28,9 @@ return program.getKotlinInfo().isSyntheticClass() && program.getKotlinInfo().asSyntheticClass().isLambda(); } + + @Override + public String getName() { + return "NoClassInitializerWithObservableSideEffects"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDirectRuntimeTypeChecks.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDirectRuntimeTypeChecks.java index b0f3766..17659f8 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDirectRuntimeTypeChecks.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDirectRuntimeTypeChecks.java
@@ -19,4 +19,9 @@ public boolean canMerge(DexProgramClass clazz) { return !runtimeTypeCheckInfo.isRuntimeCheckType(clazz); } + + @Override + public String getName() { + return "NoDirectRuntimeTypeChecks"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoEnums.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoEnums.java index c8a0aab..8bea8a4 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoEnums.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoEnums.java
@@ -27,6 +27,11 @@ } @Override + public String getName() { + return "NoEnums"; + } + + @Override public boolean canMerge(DexProgramClass program) { if (program.isEnum()) { return false;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoIndirectRuntimeTypeChecks.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoIndirectRuntimeTypeChecks.java index 7446787..8de67d6 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoIndirectRuntimeTypeChecks.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoIndirectRuntimeTypeChecks.java
@@ -65,4 +65,9 @@ } return false; } + + @Override + public String getName() { + return "NoIndirectRuntimeTypeChecks"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInnerClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInnerClasses.java index cc9f61c..1d26825 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInnerClasses.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInnerClasses.java
@@ -14,4 +14,9 @@ // TODO(b/179018501): allow merging classes with inner/outer classes. return program.getInnerClasses().isEmpty(); } + + @Override + public String getName() { + return "NoInnerClasses"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInstanceFieldAnnotations.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInstanceFieldAnnotations.java index 610af7e..229c062 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInstanceFieldAnnotations.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInstanceFieldAnnotations.java
@@ -19,4 +19,9 @@ } return true; } + + @Override + public String getName() { + return "NoInstanceFieldAnnotations"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInterfaces.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInterfaces.java index 63df0de..d6032e7 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInterfaces.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInterfaces.java
@@ -13,4 +13,9 @@ public boolean canMerge(DexProgramClass program) { return !program.isInterface(); } + + @Override + public String getName() { + return "NoInterfaces"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKeepRules.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKeepRules.java index e0a39eb..ec8a5aa 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKeepRules.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKeepRules.java
@@ -49,4 +49,9 @@ public boolean canMerge(DexProgramClass program) { return !dontMergeTypes.contains(program.getType()); } + + @Override + public String getName() { + return "NoKeepRules"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinMetadata.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinMetadata.java index 1acad7a..7783f20 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinMetadata.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinMetadata.java
@@ -29,4 +29,9 @@ .allMatch(member -> member.getKotlinMemberInfo().isNoKotlinInformation()); return true; } + + @Override + public String getName() { + return "NoKotlinMetadata"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoNativeMethods.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoNativeMethods.java index f1a278c..a32d083 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoNativeMethods.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoNativeMethods.java
@@ -14,4 +14,9 @@ public boolean canMerge(DexProgramClass program) { return !Iterables.any(program.methods(), DexEncodedMethod::isNative); } + + @Override + public String getName() { + return "NoNativeMethods"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoServiceLoaders.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoServiceLoaders.java index 1c6ae77..b1f0d99 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoServiceLoaders.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoServiceLoaders.java
@@ -26,4 +26,9 @@ return !appView.appServices().allServiceTypes().contains(program.getType()) && !allServiceImplementations.contains(program.getType()); } + + @Override + public String getName() { + return "NoServiceLoaders"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NotMatchedByNoHorizontalClassMerging.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NotMatchedByNoHorizontalClassMerging.java index bfe0f2a..8751afb 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NotMatchedByNoHorizontalClassMerging.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NotMatchedByNoHorizontalClassMerging.java
@@ -30,4 +30,9 @@ return !deadEnumLiteMaps.contains(program.getType()) && !appView.appInfo().isNoHorizontalClassMergingOfType(program.getType()); } + + @Override + public String getName() { + return "NotMatchedByNoHorizontalClassMerging"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NotVerticallyMergedIntoSubtype.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NotVerticallyMergedIntoSubtype.java index 67afbc3..92d50d1 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NotVerticallyMergedIntoSubtype.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NotVerticallyMergedIntoSubtype.java
@@ -23,4 +23,9 @@ } return !appView.verticallyMergedClasses().hasBeenMergedIntoSubtype(program.type); } + + @Override + public String getName() { + return "NotVerticallyMergedIntoSubtype"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreserveMethodCharacteristics.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreserveMethodCharacteristics.java index 4a789ba..c8bb5c6 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreserveMethodCharacteristics.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreserveMethodCharacteristics.java
@@ -28,6 +28,11 @@ */ public class PreserveMethodCharacteristics extends MultiClassPolicy { + @Override + public String getName() { + return "PreserveMethodCharacteristics"; + } + static class MethodCharacteristics { private final MethodAccessFlags accessFlags;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventMergeIntoDifferentMainDexGroups.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventMergeIntoDifferentMainDexGroups.java index 41c240f..38df5cf 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventMergeIntoDifferentMainDexGroups.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventMergeIntoDifferentMainDexGroups.java
@@ -29,4 +29,9 @@ ? mainDexInfo.getMergeKey(clazz, synthetics) : ineligibleForClassMerging(); } + + @Override + public String getName() { + return "PreventMergeIntoDifferentMainDexGroups"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventMethodImplementation.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventMethodImplementation.java index c7c57c8..b182330 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventMethodImplementation.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventMethodImplementation.java
@@ -59,6 +59,11 @@ private final ReservedInterfaceSignaturesFor reservedInterfaceSignaturesFor = new ReservedInterfaceSignaturesFor(); + @Override + public String getName() { + return "PreventMethodImplementation"; + } + private abstract static class SignaturesCache<C extends DexClass> { private final Map<DexClass, DexMethodSignatureSet> memoizedSignatures = new IdentityHashMap<>();
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java index 914fc57..78cfe13 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java
@@ -96,4 +96,9 @@ groups.addAll(restrictedClasses.values()); return groups; } + + @Override + public String getName() { + return "RespectPackageBoundaries"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameFeatureSplit.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameFeatureSplit.java index 20caa50..b3ec017 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameFeatureSplit.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameFeatureSplit.java
@@ -24,4 +24,9 @@ .getClassToFeatureSplitMap() .getFeatureSplit(clazz, appView.getSyntheticItems()); } + + @Override + public String getName() { + return "SameFeatureSplit"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameInstanceFields.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameInstanceFields.java index 13e0388..291aae5 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameInstanceFields.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameInstanceFields.java
@@ -34,6 +34,11 @@ return fields; } + @Override + public String getName() { + return "SameInstanceFields"; + } + public static class InstanceFieldInfo { private final FieldAccessFlags accessFlags;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameNestHost.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameNestHost.java index 88d2984..fc8e39c 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameNestHost.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameNestHost.java
@@ -23,4 +23,9 @@ public DexType getMergeKey(DexProgramClass clazz) { return clazz.isInANest() ? clazz.getNestHost() : dexItemFactory.objectType; } + + @Override + public String getName() { + return "SameNestHost"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameParentClass.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameParentClass.java index 12c8e31..3afa656 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameParentClass.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameParentClass.java
@@ -14,4 +14,9 @@ public DexType getMergeKey(DexProgramClass clazz) { return clazz.superType; } + + @Override + public String getName() { + return "SameParentClass"; + } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SyntheticItemsPolicy.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SyntheticItemsPolicy.java index b012897..cbc9b3d 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SyntheticItemsPolicy.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SyntheticItemsPolicy.java
@@ -48,4 +48,9 @@ // Java lambda merging is disabled. return ineligibleForClassMerging(); } + + @Override + public String getName() { + return "SyntheticItemsPolicy"; + } }
diff --git a/src/main/java/com/android/tools/r8/inspector/internal/FieldInspectorImpl.java b/src/main/java/com/android/tools/r8/inspector/internal/FieldInspectorImpl.java index 056d652e..c7e0cbb 100644 --- a/src/main/java/com/android/tools/r8/inspector/internal/FieldInspectorImpl.java +++ b/src/main/java/com/android/tools/r8/inspector/internal/FieldInspectorImpl.java
@@ -26,8 +26,8 @@ reference = Reference.field( parent.getClassReference(), - field.field.name.toString(), - Reference.typeFromDescriptor(field.field.type.toDescriptorString())); + field.getReference().name.toString(), + Reference.typeFromDescriptor(field.getReference().type.toDescriptorString())); } return reference; } @@ -45,7 +45,7 @@ @Override public Optional<ValueInspector> getInitialValue() { if (field.isStatic() && field.getStaticValue() != null) { - return Optional.of(new ValueInspectorImpl(field.getStaticValue(), field.field.type)); + return Optional.of(new ValueInspectorImpl(field.getStaticValue(), field.getReference().type)); } return Optional.empty(); }
diff --git a/src/main/java/com/android/tools/r8/inspector/internal/MethodInspectorImpl.java b/src/main/java/com/android/tools/r8/inspector/internal/MethodInspectorImpl.java index 1d868be..3c27924 100644 --- a/src/main/java/com/android/tools/r8/inspector/internal/MethodInspectorImpl.java +++ b/src/main/java/com/android/tools/r8/inspector/internal/MethodInspectorImpl.java
@@ -27,14 +27,14 @@ reference = Reference.method( parent.getClassReference(), - method.method.name.toString(), + method.getReference().name.toString(), ListUtils.map( - Arrays.asList(method.method.proto.parameters.values), + Arrays.asList(method.getReference().proto.parameters.values), param -> Reference.typeFromDescriptor(param.toDescriptorString())), - method.method.proto.returnType.isVoidType() + method.getReference().proto.returnType.isVoidType() ? null : Reference.typeFromDescriptor( - method.method.proto.returnType.toDescriptorString())); + method.getReference().proto.returnType.toDescriptorString())); } return reference; }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/TypeChecker.java b/src/main/java/com/android/tools/r8/ir/analysis/TypeChecker.java index 5926ecc..b2b6111 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/TypeChecker.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/TypeChecker.java
@@ -72,7 +72,8 @@ } TypeElement valueType = instruction.returnValue().getType(); TypeElement returnType = - TypeElement.fromDexType(method.method.proto.returnType, Nullability.maybeNull(), appView); + TypeElement.fromDexType( + method.getReference().proto.returnType, Nullability.maybeNull(), appView); if (verifyTypesHelper.isAssignable(valueType, returnType)) { return true; } @@ -80,7 +81,7 @@ if (returnType.isClassType() && valueType.isReferenceType()) { // Interface types are treated like Object according to the JVM spec. // https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.10.1.2-100 - DexClass clazz = appView.definitionFor(method.method.proto.returnType); + DexClass clazz = appView.definitionFor(method.getReference().proto.returnType); return clazz != null && clazz.isInterface(); }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java index 2b63089..d1b411a 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
@@ -102,7 +102,7 @@ Map<DexEncodedField, AbstractValue> abstractInstanceFieldValuesForClass = new IdentityHashMap<>(); for (DexEncodedField field : clazz.instanceFields()) { - FieldAccessInfo fieldAccessInfo = fieldAccessInfos.get(field.field); + FieldAccessInfo fieldAccessInfo = fieldAccessInfos.get(field.getReference()); if (fieldAccessInfo != null && !fieldAccessInfo.hasReflectiveAccess()) { abstractInstanceFieldValuesForClass.put(field, BottomValue.getInstance()); } @@ -112,14 +112,14 @@ } private boolean isAlwaysZero(DexEncodedField field) { - return !appView.appInfo().isPinned(field.field) && !nonZeroFields.contains(field); + return !appView.appInfo().isPinned(field.getReference()) && !nonZeroFields.contains(field); } void acceptClassInitializerDefaultsResult( ClassInitializerDefaultsResult classInitializerDefaultsResult) { classInitializerDefaultsResult.forEachOptimizedField( (field, value) -> { - if (!value.isDefault(field.field.type)) { + if (!value.isDefault(field.getReference().type)) { nonZeroFields.add(field); } }); @@ -223,11 +223,6 @@ >= initialAbstractValue.getAbstractionSize()) { abstractValue = UnknownValue.getInstance(); } - } else { - assert false - : "Expected abstract value of " - + field.toSourceString() - + " to be instance of NonConstantNumberValue"; } }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessAnalysis.java index a178a69..a1e3eb5 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessAnalysis.java
@@ -17,7 +17,7 @@ public void recordFieldAccess( FieldInstruction instruction, DexEncodedField field, OptimizationFeedback feedback) { - if (!field.field.type.isIntType()) { + if (!field.getReference().type.isIntType()) { return; } @@ -79,7 +79,7 @@ } if (user.isFieldPut()) { FieldInstruction fieldInstruction = user.asFieldInstruction(); - if (fieldInstruction.getField() == encodedField.field) { + if (fieldInstruction.getField() == encodedField.getReference()) { return true; } }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java index 05259ca..b11431e 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
@@ -134,7 +134,7 @@ private void clearReadsAndWritesFromFieldsOfInterest(AppInfoWithLiveness appInfo) { FieldAccessInfoCollection<?> fieldAccessInfoCollection = appInfo.getFieldAccessInfoCollection(); for (DexEncodedField field : constantFields) { - fieldAccessInfoCollection.get(field.field).asMutable().clearReads(); + fieldAccessInfoCollection.get(field.getReference()).asMutable().clearReads(); } for (DexEncodedField field : readFields.keySet()) { fieldAccessInfoCollection.get(field.getReference()).asMutable().clearWrites(); @@ -165,7 +165,7 @@ private static FieldClassification classifyField( DexEncodedField field, AppView<AppInfoWithLiveness> appView) { FieldAccessInfo fieldAccessInfo = - appView.appInfo().getFieldAccessInfoCollection().get(field.field); + appView.appInfo().getFieldAccessInfoCollection().get(field.getReference()); if (fieldAccessInfo == null || fieldAccessInfo.hasReflectiveAccess() || fieldAccessInfo.isAccessedFromMethodHandle() @@ -184,7 +184,7 @@ if (singleValue.isSingleFieldValue()) { SingleFieldValue singleFieldValue = singleValue.asSingleFieldValue(); DexField singleField = singleFieldValue.getField(); - if (singleField != field.field + if (singleField != field.getReference() && !singleFieldValue.mayHaveFinalizeMethodDirectlyOrIndirectly(appView)) { return FieldClassification.CONSTANT; }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java index 5bf0c61..f84e13d 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java
@@ -73,7 +73,7 @@ assert !isEmpty(); ConcreteMutableFieldSet rewrittenSet = new ConcreteMutableFieldSet(); for (DexEncodedField field : fields) { - DexField rewrittenFieldReference = lens.lookupField(field.field); + DexField rewrittenFieldReference = lens.lookupField(field.getReference()); DexClass holder = appView.definitionForHolder(rewrittenFieldReference); DexEncodedField rewrittenField = rewrittenFieldReference.lookupOnClass(holder); if (rewrittenField == null) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java index fc01602..13d03d5 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
@@ -150,7 +150,7 @@ // Dynamic upper bound type. TypeElement fieldType = - TypeElement.fromDexType(field.field.type, Nullability.maybeNull(), appView); + TypeElement.fromDexType(field.getReference().type, Nullability.maybeNull(), appView); TypeElement dynamicUpperBoundType = value.getDynamicUpperBoundType(appView); if (dynamicUpperBoundType.strictlyLessThan(fieldType, appView)) { if (maybeNull && dynamicUpperBoundType.isDefinitelyNotNull()) { @@ -201,7 +201,7 @@ } return appView .abstractValueFactory() - .createSingleFieldValue(field.field, computeObjectState(value)); + .createSingleFieldValue(field.getReference(), computeObjectState(value)); } /** @@ -330,7 +330,7 @@ return appView .abstractValueFactory() - .createSingleFieldValue(valuesField.field, new EnumValuesObjectState(valuesState)); + .createSingleFieldValue(valuesField.getReference(), new EnumValuesObjectState(valuesState)); } private ObjectState computeEnumInstanceObjectState(Value value) { @@ -428,7 +428,7 @@ return appView .abstractValueFactory() - .createSingleFieldValue(enumField.field, computeObjectState(value)); + .createSingleFieldValue(enumField.getReference(), computeObjectState(value)); } private ObjectState computeObjectState(Value value) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java index 65e1ea3..ec51f91 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
@@ -63,11 +63,13 @@ assert valuesCandidateAbstractValue == null || valuesCandidateAbstractValue.equals(value); valuesCandidateAbstractValue = value; - enumObjectStateBuilder.put(staticField.field, value.asSingleFieldValue().getState()); + enumObjectStateBuilder.put( + staticField.getReference(), value.asSingleFieldValue().getState()); } } else if (factory.enumMembers.isEnumField(staticField, staticField.getHolderType())) { if (value.isSingleFieldValue() && !value.asSingleFieldValue().getState().isEmpty()) { - enumObjectStateBuilder.put(staticField.field, value.asSingleFieldValue().getState()); + enumObjectStateBuilder.put( + staticField.getReference(), value.asSingleFieldValue().getState()); } } }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/EnumLiteProtoShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/EnumLiteProtoShrinker.java index 64f5bea..f0e63e9 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/proto/EnumLiteProtoShrinker.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/EnumLiteProtoShrinker.java
@@ -113,7 +113,7 @@ } DexType enumLiteCandidate = null; for (DexEncodedMethod virtualMethod : enumLiteMap.virtualMethods()) { - if (!matchesFindValueByNumberMethod(virtualMethod.method)) { + if (!matchesFindValueByNumberMethod(virtualMethod.getReference())) { return null; } if (virtualMethod.returnType() == references.enumLiteType) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java index f15ad69..3cb884a 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
@@ -109,7 +109,8 @@ @Override public boolean isReachableOrReferencedField( AppInfoWithLiveness appInfo, DexEncodedField field) { - return !wasRemoved(field.field) && super.isReachableOrReferencedField(appInfo, field); + return !wasRemoved(field.getReference()) + && super.isReachableOrReferencedField(appInfo, field); } }; }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java index c5f72a3..da0ed41 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
@@ -440,9 +440,9 @@ if (clazz != null) { DexEncodedMethod newBuilderMethod = clazz.lookupDirectMethod( - method -> method.method.name == references.newBuilderMethodName); + method -> method.getReference().name == references.newBuilderMethodName); if (newBuilderMethod != null) { - bypassClinitforInlining.add(newBuilderMethod.method); + bypassClinitforInlining.add(newBuilderMethod.getReference()); } } }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnumSwitchMapRemover.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnumSwitchMapRemover.java index 5c3692c..f8c2bf0 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnumSwitchMapRemover.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnumSwitchMapRemover.java
@@ -64,7 +64,8 @@ return null; } ObjectState state = - enumStaticFieldValues.getObjectStateForPossiblyPinnedField(enumInstanceField.field); + enumStaticFieldValues.getObjectStateForPossiblyPinnedField( + enumInstanceField.getReference()); if (state == null) { return null; }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java index b25f946..030fe3d 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
@@ -147,7 +147,7 @@ } public boolean isDynamicMethod(DexEncodedMethod encodedMethod) { - return isDynamicMethod(encodedMethod.method); + return isDynamicMethod(encodedMethod.getReference()); } public boolean isDynamicMethod(ProgramMethod method) { @@ -160,7 +160,7 @@ } public boolean isDynamicMethodBridge(DexEncodedMethod method) { - return isDynamicMethodBridge(method.method); + return isDynamicMethodBridge(method.getReference()); } public boolean isDynamicMethodBridge(ProgramMethod method) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/NonEmptyObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/NonEmptyObjectState.java index 6aacc3d..567449e 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/value/NonEmptyObjectState.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/value/NonEmptyObjectState.java
@@ -31,7 +31,7 @@ @Override public AbstractValue getAbstractFieldValue(DexEncodedField field) { - return state.getOrDefault(field.field, UnknownValue.getInstance()); + return state.getOrDefault(field.getReference(), UnknownValue.getInstance()); } @Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/ObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/ObjectState.java index 4db63a6..012a204 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/value/ObjectState.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/value/ObjectState.java
@@ -70,8 +70,8 @@ public void recordFieldHasValue(DexEncodedField field, AbstractValue abstractValue) { if (!abstractValue.isUnknown()) { - assert !state.containsKey(field.field); - state.put(field.field, abstractValue); + assert !state.containsKey(field.getReference()); + state.put(field.getReference(), abstractValue); } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java index fa42fcd..6c773a6 100644 --- a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java +++ b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
@@ -113,7 +113,7 @@ // Only check for <clinit> side effects if there is no -assumenosideeffects rule. if (appView.appInfo().hasLiveness()) { AppInfoWithLiveness appInfoWithLiveness = appView.appInfo().withLiveness(); - if (appInfoWithLiveness.noSideEffects.containsKey(resolvedField.field)) { + if (appInfoWithLiveness.noSideEffects.containsKey(resolvedField.getReference())) { return false; } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java index 506e8af..202df23 100644 --- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java +++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -973,7 +973,7 @@ || !v.hasDebugUsers() || v.debugUsers().stream().anyMatch(i -> !i.isAssume()) || v.numberOfPhiUsers() > 0 - : StringUtils.join(v.uniqueUsers(), System.lineSeparator()); + : StringUtils.join(System.lineSeparator(), v.uniqueUsers()); return true; }; return verifySSATypeLattice(wrapSSAVerifierWithStackValueHandling(verifyValue)); @@ -1091,7 +1091,7 @@ } } assert arguments.size() - == method().method.getArity() + == method().getReference().getArity() + ((method().accessFlags.isStatic() || ignoreReceiver) ? 0 : 1); return arguments; }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java index 39f2aee..ae02e8b 100644 --- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java +++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -185,7 +185,7 @@ .appInfo() .resolveMethodOnClass(dexItemFactory.objectMembers.finalize, clazz); if (finalizeResolutionResult.isSingleResolution()) { - DexMethod finalizeMethod = finalizeResolutionResult.getSingleTarget().method; + DexMethod finalizeMethod = finalizeResolutionResult.getSingleTarget().getReference(); if (finalizeMethod != dexItemFactory.enumMembers.finalize && finalizeMethod != dexItemFactory.objectMembers.finalize) { return true;
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java index 1017f53..9b68a81 100644 --- a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java +++ b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
@@ -111,7 +111,7 @@ boolean isDeadProtoExtensionField = appView.withGeneratedExtensionRegistryShrinker( - shrinker -> shrinker.isDeadProtoExtensionField(encodedField.field), false); + shrinker -> shrinker.isDeadProtoExtensionField(encodedField.getReference()), false); if (isDeadProtoExtensionField) { return false; }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java index e6f7cb6..4be3d83 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java
@@ -38,7 +38,7 @@ boolean verifyAllMethodsWithCodeExists() { for (DexProgramClass clazz : appView.appInfo().classes()) { for (DexEncodedMethod method : clazz.methods()) { - assert method.hasCode() == (nodes.get(method.method) != null); + assert method.hasCode() == (nodes.get(method.getReference()) != null); } } return true;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java index 967fee0..32be662 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
@@ -195,7 +195,7 @@ private void processInvokeWithDynamicDispatch( Invoke.Type type, DexEncodedMethod encodedTarget, ProgramMethod context) { - DexMethod target = encodedTarget.method; + DexMethod target = encodedTarget.getReference(); DexClass clazz = appView.definitionFor(target.holder); if (clazz == null) { assert false : "Unable to lookup holder of `" + target.toSourceString() + "`"; @@ -258,7 +258,7 @@ } DexEncodedField encodedField = appView.appInfo().resolveField(field).getResolvedField(); - if (encodedField == null || appView.appInfo().isPinned(encodedField.field)) { + if (encodedField == null || appView.appInfo().isPinned(encodedField.getReference())) { return; } @@ -273,7 +273,7 @@ addClassInitializerTarget(clazz); } - FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(encodedField.field); + FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(encodedField.getReference()); if (fieldAccessInfo != null && fieldAccessInfo.hasKnownWriteContexts()) { if (fieldAccessInfo.getNumberOfWriteContexts() == 1) { fieldAccessInfo.forEachWriteContext(this::addFieldReadEdge);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java index 8a63d63..682ca02 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -187,7 +187,7 @@ public DexField resolveField(DexField field) { DexEncodedField resolvedField = appView.appInfoForDesugaring().resolveField(field).getResolvedField(); - return resolvedField == null ? field : resolvedField.field; + return resolvedField == null ? field : resolvedField.getReference(); } private void computeInitializers() {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java index bb8e12a..4ba4555 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
@@ -95,6 +95,9 @@ // The non-synthetic holder is not scheduled. It will be processed once holder is scheduled. return; } + if (method.getDefinition().isAbstract()) { + return; + } terminalFutures.add( ThreadUtils.processAsynchronously( () ->
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java index 93c61ab..e6bc084 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -542,7 +542,7 @@ } int originalNumberOfArguments = - method.method.proto.parameters.values.length + method.getReference().proto.parameters.values.length + argumentsInfo.numberOfRemovedArguments() + (method.isStatic() ? 0 : 1) - prototypeChanges.numberOfExtraParameters(); @@ -562,14 +562,14 @@ DexType argType; if (argumentInfo.isRewrittenTypeInfo()) { RewrittenTypeInfo argumentRewrittenTypeInfo = argumentInfo.asRewrittenTypeInfo(); - assert method.method.proto.getParameter(usedArgumentIndex) + assert method.getReference().proto.getParameter(usedArgumentIndex) == argumentRewrittenTypeInfo.getNewType(); // The old type is used to prevent that a changed value from reference to primitive // type breaks IR building. Rewriting from the old to the new type will be done in the // IRConverter (typically through the lensCodeRewriter). argType = argumentRewrittenTypeInfo.getOldType(); } else { - argType = method.method.proto.getParameter(usedArgumentIndex); + argType = method.getReference().proto.getParameter(usedArgumentIndex); } usedArgumentIndex++; writeCallback.accept(register, argType); @@ -585,7 +585,7 @@ } for (ExtraParameter extraParameter : prototypeChanges.getExtraParameters()) { - DexType argType = method.method.proto.getParameter(usedArgumentIndex); + DexType argType = method.getReference().proto.getParameter(usedArgumentIndex); TypeElement type = extraParameter.getTypeElement(appView, argType); register += type.requiredRegisters(); usedArgumentIndex++; @@ -1827,7 +1827,7 @@ public void addReturn(int value) { DexType returnType = method.getDefinition().returnType(); if (returnType.isVoidType()) { - assert prototypeChanges.hasBeenChangedToReturnVoid(appView); + assert prototypeChanges.hasBeenChangedToReturnVoid(appView.dexItemFactory()); addReturn(); } else { ValueTypeConstraint returnTypeConstraint =
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java index 54b0a66..0530046 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -1196,7 +1196,7 @@ + ExceptionUtils.getMainStackTrace(); assert !method.isProcessed() || !appView.enableWholeProgramOptimizations() - || !appView.appInfo().withLiveness().isNeverReprocessMethod(method.method) + || !appView.appInfo().withLiveness().isNeverReprocessMethod(method.getReference()) : "Illegal reprocessing due to -neverreprocess rule: " + context.toSourceString(); if (typeChecker != null && !typeChecker.check(code)) { @@ -1621,7 +1621,7 @@ timing.end(); } - if (appView.appInfo().withLiveness().isPinned(code.method().method)) { + if (appView.appInfo().withLiveness().isPinned(code.method().getReference())) { return; } @@ -1785,7 +1785,7 @@ return; } // Only constructors with certain signatures. - DexTypeList paramTypes = code.method().method.proto.parameters; + DexTypeList paramTypes = code.method().getReference().proto.parameters; if (paramTypes.size() != 3 || paramTypes.values[0] != options.itemFactory.doubleType || paramTypes.values[1] != options.itemFactory.doubleType || @@ -1967,7 +1967,7 @@ printer.end("cfg"); } if (options.extensiveLoggingFilter.size() > 0 - && options.extensiveLoggingFilter.contains(code.method().method.toSourceString())) { + && options.extensiveLoggingFilter.contains(code.method().getReference().toSourceString())) { String current = code.toString(); System.out.println(); System.out.println("-----------------------------------------------------------------------");
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java index b6609b8..66e7ff7 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -280,7 +280,7 @@ } ConstInstruction constantReturnMaterializingInstruction = null; - if (prototypeChanges.hasBeenChangedToReturnVoid(appView) + if (prototypeChanges.hasBeenChangedToReturnVoid(appView.dexItemFactory()) && invoke.outValue() != null) { constantReturnMaterializingInstruction = prototypeChanges.getConstantReturn(code, invoke.getPosition()); @@ -297,7 +297,7 @@ } Value newOutValue = - prototypeChanges.hasBeenChangedToReturnVoid(appView) + prototypeChanges.hasBeenChangedToReturnVoid(appView.dexItemFactory()) ? null : makeOutValue(invoke, code); @@ -596,7 +596,7 @@ if (ret.isReturnVoid()) { break; } - DexType returnType = code.method().method.proto.returnType; + DexType returnType = code.method().getReference().proto.returnType; Value retValue = ret.returnValue(); DexType initialType = retValue.getType().isPrimitiveType()
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java b/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java index 4c073e1..d9f8625 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java
@@ -152,7 +152,7 @@ + ", its imprecise type is: " + stillImprecise.get(0).getType(), code.origin, - new MethodPosition(code.method().method.asMethodReference()))); + new MethodPosition(code.method().getReference().asMethodReference()))); } }
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 5cd32f2..2fc5c3a 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
@@ -1059,10 +1059,15 @@ factory.intType); DexMethod method = factory.createMethod(type, proto, name); addProvider( - new MethodGenerator( - method, - BackportedMethods::IntegerMethods_parseIntSubsequenceWithRadix, - "parseIntSubsequenceWithRadix")); + appView.options().canParseNumbersWithPlusPrefix() + ? new MethodGenerator( + method, + BackportedMethods::IntegerMethods_parseIntSubsequenceWithRadix, + "parseIntSubsequenceWithRadix") + : new MethodGenerator( + method, + BackportedMethods::IntegerMethods_parseIntSubsequenceWithRadixDalvik, + "parseIntSubsequenceWithRadix")); // Long type = factory.boxedLongType; @@ -1077,10 +1082,15 @@ factory.intType); method = factory.createMethod(type, proto, name); addProvider( - new MethodGenerator( - method, - BackportedMethods::LongMethods_parseLongSubsequenceWithRadix, - "parseLongSubsequenceWithRadix")); + appView.options().canParseNumbersWithPlusPrefix() + ? new MethodGenerator( + method, + BackportedMethods::LongMethods_parseLongSubsequenceWithRadix, + "parseLongSubsequenceWithRadix") + : new MethodGenerator( + method, + BackportedMethods::LongMethods_parseLongSubsequenceWithRadixDalvik, + "parseLongSubsequenceWithRadix")); // long Long.parseUnsignedLong(CharSequence s, int beginIndex, int endIndex, int radix) name = factory.createString("parseUnsignedLong");
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfClassDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfClassDesugaringEventConsumer.java index d5acaa7..9b02ab5 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/CfClassDesugaringEventConsumer.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/CfClassDesugaringEventConsumer.java
@@ -5,6 +5,7 @@ package com.android.tools.r8.ir.desugar; import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.D8MethodProcessor; public abstract class CfClassDesugaringEventConsumer implements RecordDesugaringEventConsumer { @@ -25,6 +26,11 @@ public void acceptRecordClass(DexProgramClass recordClass) { methodProcessor.scheduleDesugaredMethodsForProcessing(recordClass.programMethods()); } + + @Override + public void acceptRecordMethod(ProgramMethod method) { + assert false; + } } // TODO(b/): Implement R8CfClassDesugaringEventConsumer
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java index a95569e..a0c4c64 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
@@ -64,6 +64,11 @@ } @Override + public void acceptRecordMethod(ProgramMethod method) { + assert false; + } + + @Override public void acceptBackportedMethod(ProgramMethod backportedMethod, ProgramMethod context) { assert false; } @@ -119,6 +124,11 @@ } @Override + public void acceptRecordMethod(ProgramMethod method) { + methodProcessor.scheduleDesugaredMethodForProcessing(method); + } + + @Override public void acceptInvokeSpecialBridgeInfo(InvokeSpecialBridgeInfo info) { synchronized (pendingInvokeSpecialBridges) { assert !pendingInvokeSpecialBridges.containsKey(info.getNewDirectMethod().getReference()); @@ -242,6 +252,11 @@ } @Override + public void acceptRecordMethod(ProgramMethod method) { + assert false : "TODO(b/179146128): To be implemented"; + } + + @Override public void acceptBackportedMethod(ProgramMethod backportedMethod, ProgramMethod context) { // Intentionally empty. The backported method will be hit by the tracing in R8 as if it was // present in the input code, and thus nothing needs to be done.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java index 6200603..6ef420d 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -27,6 +27,7 @@ import com.android.tools.r8.ir.synthetic.ExceptionThrowingSourceCode; import com.android.tools.r8.ir.synthetic.SynthesizedCode; import com.android.tools.r8.position.MethodPosition; +import com.android.tools.r8.utils.BooleanBox; import com.android.tools.r8.utils.IterableUtils; import com.android.tools.r8.utils.MethodSignatureEquivalence; import com.android.tools.r8.utils.WorkList; @@ -125,7 +126,7 @@ ClassInfo parent, ImmutableList<DexClassAndMethod> forwardedMethodTargets, EmulatedInterfaceInfo emulatedInterfaceInfo) { - return forwardedMethodTargets.isEmpty() + return forwardedMethodTargets.isEmpty() && emulatedInterfaceInfo.isEmpty() ? parent : new ClassInfo(parent, forwardedMethodTargets, emulatedInterfaceInfo); } @@ -204,6 +205,40 @@ } } + // Emulated interfaces together with the generic signatures. + static class EmulatedInterfaces { + static EmulatedInterfaces EMPTY = new EmulatedInterfaces(ImmutableSet.of()); + + final Set<DexType> emulatedInterfaces; + + EmulatedInterfaces(DexType emulatedInterface) { + this.emulatedInterfaces = ImmutableSet.of(emulatedInterface); + } + + private EmulatedInterfaces(Set<DexType> emulatedInterfaces) { + this.emulatedInterfaces = emulatedInterfaces; + } + + boolean isEmpty() { + return emulatedInterfaces.isEmpty(); + } + + boolean contains(DexType type) { + return emulatedInterfaces.contains(type); + } + + Set<DexType> getEmulatedInterfaces() { + return emulatedInterfaces; + } + + EmulatedInterfaces merge(EmulatedInterfaces other) { + ImmutableSet.Builder<DexType> newEmulatedInterfaces = ImmutableSet.builder(); + newEmulatedInterfaces.addAll(emulatedInterfaces); + newEmulatedInterfaces.addAll(other.emulatedInterfaces); + return new EmulatedInterfaces(newEmulatedInterfaces.build()); + } + } + // List of emulated interfaces and corresponding signatures which may require forwarding methods. // If one of the signatures has an override, then the class holding the override is required to // add the forwarding methods for all signatures, and introduce the corresponding emulated @@ -213,13 +248,13 @@ private static class EmulatedInterfaceInfo { static final EmulatedInterfaceInfo EMPTY = - new EmulatedInterfaceInfo(MethodSignatures.EMPTY, ImmutableSet.of()); + new EmulatedInterfaceInfo(MethodSignatures.EMPTY, EmulatedInterfaces.EMPTY); final MethodSignatures signatures; - final ImmutableSet<DexType> emulatedInterfaces; + final EmulatedInterfaces emulatedInterfaces; private EmulatedInterfaceInfo( - MethodSignatures methodsToForward, ImmutableSet<DexType> emulatedInterfaces) { + MethodSignatures methodsToForward, EmulatedInterfaces emulatedInterfaces) { this.signatures = methodsToForward; this.emulatedInterfaces = emulatedInterfaces; } @@ -231,17 +266,18 @@ if (other.isEmpty()) { return this; } - ImmutableSet.Builder<DexType> newEmulatedInterfaces = ImmutableSet.builder(); - newEmulatedInterfaces.addAll(emulatedInterfaces); - newEmulatedInterfaces.addAll(other.emulatedInterfaces); return new EmulatedInterfaceInfo( - signatures.merge(other.signatures), newEmulatedInterfaces.build()); + signatures.merge(other.signatures), emulatedInterfaces.merge(other.emulatedInterfaces)); } public boolean isEmpty() { assert !emulatedInterfaces.isEmpty() || signatures.isEmpty(); return emulatedInterfaces.isEmpty(); } + + boolean contains(DexType type) { + return emulatedInterfaces.contains(type); + } } // Helper to keep track of the direct active subclass and nearest program subclass for reporting. @@ -375,7 +411,7 @@ assert needsLibraryInfo(); MethodSignatures signatures = getDefaultMethods(iface); EmulatedInterfaceInfo emulatedInterfaceInfo = - new EmulatedInterfaceInfo(signatures, ImmutableSet.of(iface.type)); + new EmulatedInterfaceInfo(signatures, new EmulatedInterfaces(iface.type)); return interfaceInfo.withEmulatedInterfaceInfo(emulatedInterfaceInfo); } @@ -384,7 +420,7 @@ Set<Wrapper<DexMethod>> defaultMethods = new HashSet<>(iface.getMethodCollection().numberOfVirtualMethods()); for (DexEncodedMethod method : iface.virtualMethods(DexEncodedMethod::isDefaultMethod)) { - defaultMethods.add(equivalence.wrap(method.method)); + defaultMethods.add(equivalence.wrap(method.getReference())); } return MethodSignatures.create(defaultMethods); } @@ -422,14 +458,13 @@ // implement the interface and the emulated one for correct emulated dispatch. // The class signature won't include the correct type parameters for the duplicated interfaces, // i.e., there will be foo.A instead of foo.A<K,V>, but such parameters are unused. - private void duplicateEmulatedInterfaces( - DexClass clazz, ImmutableSet<DexType> emulatedInterfaces) { + private void duplicateEmulatedInterfaces(DexClass clazz, EmulatedInterfaces emulatedInterfaces) { if (clazz.isNotProgramClass()) { return; } - Set<DexType> filtered = new HashSet<>(emulatedInterfaces); + Set<DexType> filtered = new HashSet<>(emulatedInterfaces.getEmulatedInterfaces()); WorkList<DexType> workList = WorkList.newIdentityWorkList(); - for (DexType emulatedInterface : emulatedInterfaces) { + for (DexType emulatedInterface : emulatedInterfaces.getEmulatedInterfaces()) { DexClass iface = appView.definitionFor(emulatedInterface); if (iface != null) { assert iface.isLibraryClass() @@ -447,7 +482,7 @@ workList.addIfNotSeen(iface.getInterfaces()); } - for (DexType emulatedInterface : emulatedInterfaces) { + for (DexType emulatedInterface : emulatedInterfaces.getEmulatedInterfaces()) { DexClass s = appView.definitionFor(emulatedInterface); if (s != null) { s = appView.definitionFor(s.superType); @@ -458,13 +493,17 @@ } } + // Collect the signatures for the emulated interfaces to add. + Map<DexType, GenericSignature.ClassTypeSignature> signatures = new IdentityHashMap<>(); + collectEmulatedInterfaces(clazz, filtered, signatures); // We need to introduce them in deterministic order for deterministic compilation. ArrayList<DexType> sortedEmulatedInterfaces = new ArrayList<>(filtered); Collections.sort(sortedEmulatedInterfaces); List<GenericSignature.ClassTypeSignature> extraInterfaceSignatures = new ArrayList<>(); for (DexType extraInterface : sortedEmulatedInterfaces) { - extraInterfaceSignatures.add( - new GenericSignature.ClassTypeSignature(rewriter.getEmulatedInterface(extraInterface))); + GenericSignature.ClassTypeSignature signature = signatures.get(extraInterface); + assert signature != null; + extraInterfaceSignatures.add(signature); } // The emulated interface might already be implemented if the input class has gone through // library desugaring already. @@ -489,6 +528,75 @@ clazz.asProgramClass().addExtraInterfaces(extraInterfaceSignatures); } + private void collectEmulatedInterfaces( + DexClass clazz, + Set<DexType> emulatesInterfaces, + Map<DexType, GenericSignature.ClassTypeSignature> extraInterfaceSignatures) { + // TODO(b/182329331): Only handle type arguments for Cf to Cf desugar. + if (appView.options().cfToCfDesugar && clazz.validInterfaceSignatures()) { + clazz.forEachImmediateSupertype( + (type, signature) -> { + if (emulatesInterfaces.contains(type)) { + extraInterfaceSignatures.put( + type, + new GenericSignature.ClassTypeSignature( + rewriter.getEmulatedInterface(type), signature.typeArguments())); + } + collectEmulatedInterfacesWithPropagatedTypeArguments( + type, signature.typeArguments(), emulatesInterfaces, extraInterfaceSignatures); + }); + } else { + clazz.forEachImmediateSupertype( + (type) -> { + if (emulatesInterfaces.contains(type)) { + extraInterfaceSignatures.put( + type, + new GenericSignature.ClassTypeSignature(rewriter.getEmulatedInterface(type))); + } + collectEmulatedInterfacesWithPropagatedTypeArguments( + type, null, emulatesInterfaces, extraInterfaceSignatures); + }); + } + } + + private void collectEmulatedInterfacesWithPropagatedTypeArguments( + DexType type, + List<GenericSignature.FieldTypeSignature> typeArguments, + Set<DexType> emulatesInterfaces, + Map<DexType, GenericSignature.ClassTypeSignature> extraInterfaceSignatures) { + DexClass clazz = appView.definitionFor(type); + if (clazz == null) { + return; + } + // TODO(b/182329331): Only handle type arguments for Cf to Cf desugar. + if (appView.options().cfToCfDesugar && clazz.validInterfaceSignatures()) { + assert typeArguments != null; + clazz.forEachImmediateSupertypeWithAppliedTypeArguments( + typeArguments, + (iface, signature) -> { + if (emulatesInterfaces.contains(iface)) { + extraInterfaceSignatures.put( + iface, + new GenericSignature.ClassTypeSignature( + rewriter.getEmulatedInterface(iface), signature)); + } + collectEmulatedInterfacesWithPropagatedTypeArguments( + iface, signature, emulatesInterfaces, extraInterfaceSignatures); + }); + } else { + assert typeArguments == null; + clazz.forEachImmediateSupertype( + iface -> { + if (emulatesInterfaces.contains(iface)) { + extraInterfaceSignatures.put( + iface, + new GenericSignature.ClassTypeSignature(rewriter.getEmulatedInterface(iface))); + } + collectEmulatedInterfacesWithPropagatedTypeArguments( + iface, null, emulatesInterfaces, extraInterfaceSignatures); + }); + } + } // If any of the signature would lead to a different behavior than the default method on the // emulated interface, we need to resolve the forwarding methods. private boolean shouldResolveForwardingMethodsForEmulatedInterfaces( @@ -501,7 +609,7 @@ } DexClass resolvedHolder = resolutionResult.asSingleResolution().getResolvedHolder(); if (!resolvedHolder.isLibraryClass() - && !emulatedInterfaceInfo.emulatedInterfaces.contains(resolvedHolder.type)) { + && !emulatedInterfaceInfo.contains(resolvedHolder.type)) { return true; } } @@ -533,27 +641,44 @@ // the 'addForward' call-back is called with the target of the forward. private void resolveForwardForSignature( DexClass clazz, DexMethod method, Consumer<DexClassAndMethod> addForward) { - // Resolve the default method with base type as the symbolic holder as call sites are not known. - // The dispatch target is then looked up from the possible "instance" class. - // Doing so can cause an invalid invoke to become valid (at runtime resolution at a subtype - // might have failed which is hidden by the insertion of the forward method). However, not doing - // so could cause valid dispatches to become invalid by resolving to private overrides. AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring(); - DexClassAndMethod virtualDispatchTarget = - appInfo - .resolveMethodOnInterface(method.holder, method) - .lookupVirtualDispatchTarget(clazz, appInfo); - if (virtualDispatchTarget == null) { - // If no target is found due to multiple default method targets, preserve ICCE behavior. - ResolutionResult resolutionFromSubclass = appInfo.resolveMethodOn(clazz, method); - if (resolutionFromSubclass.isIncompatibleClassChangeErrorResult()) { - addICCEThrowingMethod(method, clazz); + ResolutionResult resolutionResult = appInfo.resolveMethodOn(clazz, method); + if (resolutionResult.isFailedResolution() + || resolutionResult.asSuccessfulMemberResolutionResult().getResolvedMember().isStatic()) { + // When doing resolution we may find a static or private targets and bubble up the failed + // resolution to preserve ICCE even though the resolution actually succeeded, ie. finding a + // method with the same name and descriptor. For invoke-virtual and invoke-interface, the + // selected method will only consider instance methods. + BooleanBox staticTarget = new BooleanBox(true); + if (resolutionResult.isFailedResolution()) { + resolutionResult + .asFailedResolution() + .forEachFailureDependency(target -> staticTarget.and(target.isStatic())); + } else if (resolutionResult.isSuccessfulMemberResolutionResult()) { + staticTarget.set( + resolutionResult.asSuccessfulMemberResolutionResult().getResolvedMember().isStatic()); + } + if (staticTarget.isAssigned() && staticTarget.isTrue()) { + resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method); + } + if (resolutionResult.isFailedResolution()) { + if (resolutionResult.isIncompatibleClassChangeErrorResult()) { + addICCEThrowingMethod(method, clazz); + return; + } + if (resolutionResult.isNoSuchMethodErrorResult(clazz, appInfo)) { + addNoSuchMethodErrorThrowingMethod(method, clazz); + return; + } + assert resolutionResult.isIllegalAccessErrorResult(clazz, appInfo); + addIllegalAccessErrorThrowingMethod(method, clazz); return; } - assert resolutionFromSubclass.isFailedResolution() - || resolutionFromSubclass.getSingleTarget().isPrivateMethod(); - return; } + assert resolutionResult.isSuccessfulMemberResolutionResult(); + DexClassAndMethod virtualDispatchTarget = + resolutionResult.lookupVirtualDispatchTarget(clazz, appInfo); + assert virtualDispatchTarget != null; // Don't forward if the target is explicitly marked as 'dont-rewrite' if (dontRewrite(virtualDispatchTarget)) { @@ -612,6 +737,18 @@ } private void addICCEThrowingMethod(DexMethod method, DexClass clazz) { + addThrowingMethod(method, clazz, dexItemFactory.icceType); + } + + private void addIllegalAccessErrorThrowingMethod(DexMethod method, DexClass clazz) { + addThrowingMethod(method, clazz, dexItemFactory.illegalAccessErrorType); + } + + private void addNoSuchMethodErrorThrowingMethod(DexMethod method, DexClass clazz) { + addThrowingMethod(method, clazz, dexItemFactory.noSuchMethodErrorType); + } + + private void addThrowingMethod(DexMethod method, DexClass clazz, DexType errorType) { if (!clazz.isProgramClass()) { return; } @@ -625,8 +762,7 @@ ParameterAnnotationsList.empty(), new SynthesizedCode( callerPosition -> - new ExceptionThrowingSourceCode( - clazz.type, method, callerPosition, dexItemFactory.icceType)), + new ExceptionThrowingSourceCode(clazz.type, method, callerPosition, errorType)), true); addSyntheticMethod(clazz.asProgramClass(), newEncodedMethod); } @@ -644,7 +780,7 @@ "Attempt to add forwarding method that conflicts with existing method.", null, clazz.getOrigin(), - new MethodPosition(methodOnSelf.method.asMethodReference())); + new MethodPosition(methodOnSelf.getReference().asMethodReference())); } // NOTE: Never add a forwarding method to methods of classes unknown or coming from android.jar @@ -696,8 +832,8 @@ SignaturesInfo signatures = visitLibraryClassInfo(clazz.superType); // The class may inherit emulated interface info from its program superclass if the latter // did not require to resolve the forwarding methods for emualted interfaces. - signatures = signatures.withEmulatedInterfaceInfo(superInfo.emulatedInterfaceInfo); assert superInfo.isEmpty() || signatures.isEmpty(); + signatures = signatures.withEmulatedInterfaceInfo(superInfo.emulatedInterfaceInfo); for (DexType iface : clazz.interfaces.values) { signatures = signatures.merge(visitInterfaceInfo(iface, thisContext)); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java index fd4abda..5760bd2 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
@@ -267,7 +267,7 @@ private static boolean hasVirtualMethodWithSignature(DexClass clazz, DexEncodedMethod method) { for (DexEncodedMethod existingMethod : clazz.virtualMethods()) { - if (existingMethod.method.equals(method.method)) { + if (existingMethod.getReference().equals(method.getReference())) { return true; } }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DefaultMethodsHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/DefaultMethodsHelper.java index 07277bc..838374d 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/DefaultMethodsHelper.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/DefaultMethodsHelper.java
@@ -44,7 +44,7 @@ DexMethod getSingleCandidate(DexMethod method) { DexMethod candidate = null; for (DexEncodedMethod encodedMethod : live) { - DexMethod current = encodedMethod.method; + DexMethod current = encodedMethod.getReference(); if (current.proto == method.proto && current.name == method.name) { if (candidate != null) { return null;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java index f2f255a..4f05b2e 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
@@ -341,10 +341,10 @@ private ProgramMethod generateCallbackMethod( DexEncodedMethod originalMethod, DexProgramClass clazz) { DexMethod methodToInstall = - methodWithVivifiedTypeInSignature(originalMethod.method, clazz.type, appView); + methodWithVivifiedTypeInSignature(originalMethod.getReference(), clazz.type, appView); CfCode cfCode = new APIConverterWrapperCfCodeProvider( - appView, originalMethod.method, null, this, clazz.isInterface()) + appView, originalMethod.getReference(), null, this, clazz.isInterface()) .generateCfCode(); DexEncodedMethod newMethod = wrapperSynthesizor.newSynthesizedMethod(methodToInstall, originalMethod, cfCode);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java index 8a6624e..4f4673a 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
@@ -264,7 +264,7 @@ if (!appView.options().encodeChecksums) { return DexProgramClass::invalidChecksumRequest; } - return c -> method.method.hashCode(); + return c -> method.getReference().hashCode(); } // Used by the ListOfBackportedMethods utility. @@ -331,7 +331,7 @@ } DexEncodedMethod singleTarget = resolutionResult.getSingleTarget(); assert singleTarget != null; - retarget = getRetargetLibraryMember(singleTarget.method); + retarget = getRetargetLibraryMember(singleTarget.getReference()); } return retarget; } @@ -622,7 +622,8 @@ // Dispatch holder. DexType holderType = dispatchHolderTypeFor(emulatedDispatchMethod); DexEncodedMethod dispatchMethod = - generateHolderDispatchMethod(emulatedDispatchMethod, holderType, itfMethod.method); + generateHolderDispatchMethod( + emulatedDispatchMethod, holderType, itfMethod.getReference()); synthesizeClassWithUniqueMethod( builder, holderAccessFlags,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java index ce4f61a..f5845d4 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
@@ -239,7 +239,9 @@ DexAnnotationSet.empty(), DexEncodedField.EMPTY_ARRAY, // No static fields. new DexEncodedField[] {wrapperField}, - new DexEncodedMethod[] {synthesizeConstructor(wrapperField.field), conversionMethod}, + new DexEncodedMethod[] { + synthesizeConstructor(wrapperField.getReference()), conversionMethod + }, virtualMethods, factory.getSkipNameValidationForTesting(), DexProgramClass::checksumFromType); @@ -275,21 +277,17 @@ DexMethod methodToInstall = factory.createMethod( wrapperField.getHolderType(), - dexEncodedMethod.method.proto, - dexEncodedMethod.method.name); + dexEncodedMethod.getReference().proto, + dexEncodedMethod.getReference().name); CfCode cfCode; if (dexEncodedMethod.isFinal()) { invalidWrappers.add(wrapperField.getHolderType()); - finalMethods.add(dexEncodedMethod.method); + finalMethods.add(dexEncodedMethod.getReference()); continue; } else { cfCode = new APIConverterVivifiedWrapperCfCodeProvider( - appView, - methodToInstall, - wrapperField.field, - converter, - isInterface) + appView, methodToInstall, wrapperField.getReference(), converter, isInterface) .generateCfCode(); } DexEncodedMethod newDexEncodedMethod = @@ -320,16 +318,20 @@ boolean isInterface = holderClass == null || holderClass.isInterface(); DexMethod methodToInstall = DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature( - dexEncodedMethod.method, wrapperField.getHolderType(), appView); + dexEncodedMethod.getReference(), wrapperField.getHolderType(), appView); CfCode cfCode; if (dexEncodedMethod.isFinal()) { invalidWrappers.add(wrapperField.getHolderType()); - finalMethods.add(dexEncodedMethod.method); + finalMethods.add(dexEncodedMethod.getReference()); continue; } else { cfCode = new APIConverterWrapperCfCodeProvider( - appView, dexEncodedMethod.method, wrapperField.field, converter, isInterface) + appView, + dexEncodedMethod.getReference(), + wrapperField.getReference(), + converter, + isInterface) .generateCfCode(); } DexEncodedMethod newDexEncodedMethod = @@ -398,7 +400,7 @@ // This looks quadratic but given the size of the collections met in practice for // desugared libraries (Max ~15) it does not matter. for (DexEncodedMethod alreadyImplementedMethod : implementedMethods) { - if (alreadyImplementedMethod.method.match(virtualMethod.method)) { + if (alreadyImplementedMethod.getReference().match(virtualMethod.getReference())) { alreadyAdded = true; break; }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java index a1c0d58..f6a653b 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -198,8 +198,10 @@ clazz.forEachMethod( m -> { if (m.isDefaultMethod()) { - appInfo.dexItemFactory().registerTypeNeededForDesugaring(m.method.proto.returnType); - for (DexType param : m.method.proto.parameters.values) { + appInfo + .dexItemFactory() + .registerTypeNeededForDesugaring(m.getReference().proto.returnType); + for (DexType param : m.getReference().proto.parameters.values) { appInfo.dexItemFactory().registerTypeNeededForDesugaring(param); } } @@ -216,7 +218,7 @@ if (emulatedInterfaceClass != null) { for (DexEncodedMethod encodedMethod : emulatedInterfaceClass.methods(DexEncodedMethod::isDefaultMethod)) { - emulatedMethods.add(encodedMethod.method.name); + emulatedMethods.add(encodedMethod.getReference().name); } } } @@ -1243,8 +1245,7 @@ InterfaceProcessorNestedGraphLens.builder(); Map<DexClass, DexProgramClass> classMapping = processInterfaces(builder, flavour, graphLensBuilder, synthesizedMethods::add); - InterfaceProcessorNestedGraphLens graphLens = - graphLensBuilder.build(appView.dexItemFactory(), appView.graphLens()); + InterfaceProcessorNestedGraphLens graphLens = graphLensBuilder.build(appView); if (appView.enableWholeProgramOptimizations() && graphLens != null) { appView.setGraphLens(graphLens); } @@ -1476,7 +1477,7 @@ // Hide by virtual methods of this interface. for (DexEncodedMethod virtual : definedInterface.virtualMethods()) { - helper.hideMatches(virtual.method); + helper.hideMatches(virtual.getReference()); } // Add all default methods of this interface.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriterFixup.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriterFixup.java index ed8077a..bb0de67 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriterFixup.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriterFixup.java
@@ -53,8 +53,7 @@ return null; } // Map default methods to their companion methods. - DexMethod mappedMethod = - graphLens.getExtraOriginalMethodSignatures().getRepresentativeKey(method); + DexMethod mappedMethod = graphLens.getExtraNewMethodSignatures().getRepresentativeValue(method); if (mappedMethod != null) { return mappedMethod; }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java index d20eee7..0199730 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -37,9 +37,9 @@ import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature; import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature; import com.android.tools.r8.graph.GraphLens; -import com.android.tools.r8.graph.GraphLens.NestedGraphLens; import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.MethodCollection; +import com.android.tools.r8.graph.NestedGraphLens; import com.android.tools.r8.graph.ParameterAnnotationsList; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.Invoke.Type; @@ -256,7 +256,8 @@ implMethod.copyMetadata(virtual); virtual.setDefaultInterfaceMethodImplementation(implMethod); companionMethods.add(implMethod); - graphLensBuilder.recordCodeMovedToCompanionClass(method.getReference(), implMethod.method); + graphLensBuilder.recordCodeMovedToCompanionClass( + method.getReference(), implMethod.getReference()); } // Remove bridge methods. @@ -324,7 +325,8 @@ newFlags.promoteToStatic(); DexMethod companionMethod = - rewriter.privateAsMethodOfCompanionClass(oldMethod, appView.dexItemFactory()); + InterfaceMethodRewriter.privateAsMethodOfCompanionClass( + oldMethod, appView.dexItemFactory()); Code code = definition.getCode(); if (code == null) { @@ -397,7 +399,7 @@ // also be kept (such a situation can happen if the vertical class merger merges two interfaces). private boolean interfaceMethodRemovalChangesApi(DexEncodedMethod method, DexClass iface) { if (appView.enableWholeProgramOptimizations()) { - if (appView.appInfo().withLiveness().isPinned(method.method)) { + if (appView.appInfo().withLiveness().isPinned(method.getReference())) { return true; } } @@ -411,7 +413,7 @@ if (clazz == null || !seenBefore.add(clazz.type)) { continue; } - if (clazz.lookupVirtualMethod(method.method) != null) { + if (clazz.lookupVirtualMethod(method.getReference()) != null) { return false; } addSuperTypes(clazz, worklist); @@ -433,32 +435,24 @@ if (method.accessFlags.isNative()) { throw new Unimplemented("Native interface methods are not yet supported."); } - return method.accessFlags.isStatic() && !rewriter.factory.isClassConstructor(method.method); + return method.accessFlags.isStatic() + && !rewriter.factory.isClassConstructor(method.getReference()); } // Specific lens which remaps invocation types to static since all rewrites performed here // are to static companion methods. public static class InterfaceProcessorNestedGraphLens extends NestedGraphLens { - private BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> - extraOriginalMethodSignatures; + private BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> extraNewMethodSignatures; public InterfaceProcessorNestedGraphLens( - Map<DexType, DexType> typeMap, - Map<DexMethod, DexMethod> methodMap, + AppView<?> appView, BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap, - BidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures, - BidirectionalOneToOneMap<DexMethod, DexMethod> extraOriginalMethodSignatures, - GraphLens previousLens, - DexItemFactory dexItemFactory) { - super( - typeMap, - methodMap, - fieldMap, - originalMethodSignatures, - previousLens, - dexItemFactory); - this.extraOriginalMethodSignatures = extraOriginalMethodSignatures; + BidirectionalManyToOneRepresentativeMap<DexMethod, DexMethod> methodMap, + Map<DexType, DexType> typeMap, + BidirectionalOneToOneMap<DexMethod, DexMethod> extraNewMethodSignatures) { + super(appView, fieldMap, methodMap, typeMap); + this.extraNewMethodSignatures = extraNewMethodSignatures; } public static InterfaceProcessorNestedGraphLens find(GraphLens lens) { @@ -476,14 +470,14 @@ } public void toggleMappingToExtraMethods() { - BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> tmp = originalMethodSignatures; - this.originalMethodSignatures = extraOriginalMethodSignatures; - this.extraOriginalMethodSignatures = tmp; + BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> tmp = newMethodSignatures; + this.newMethodSignatures = extraNewMethodSignatures; + this.extraNewMethodSignatures = tmp; } public BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> - getExtraOriginalMethodSignatures() { - return extraOriginalMethodSignatures; + getExtraNewMethodSignatures() { + return extraNewMethodSignatures; } @Override @@ -503,14 +497,14 @@ @Override protected DexMethod internalGetPreviousMethodSignature(DexMethod method) { - return extraOriginalMethodSignatures.getRepresentativeValueOrDefault( - method, originalMethodSignatures.getRepresentativeValueOrDefault(method, method)); + return extraNewMethodSignatures.getRepresentativeKeyOrDefault( + method, newMethodSignatures.getRepresentativeKeyOrDefault(method, method)); } @Override protected DexMethod internalGetNextMethodSignature(DexMethod method) { - return originalMethodSignatures.getRepresentativeKeyOrDefault( - method, extraOriginalMethodSignatures.getRepresentativeKeyOrDefault(method, method)); + return newMethodSignatures.getRepresentativeValueOrDefault( + method, extraNewMethodSignatures.getRepresentativeValueOrDefault(method, method)); } @Override @@ -522,33 +516,24 @@ return new Builder(); } - public static class Builder extends NestedGraphLens.Builder { + public static class Builder extends GraphLens.Builder { - private final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> - extraOriginalMethodSignatures = new BidirectionalOneToOneHashMap<>(); + private final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> extraNewMethodSignatures = + new BidirectionalOneToOneHashMap<>(); public void recordCodeMovedToCompanionClass(DexMethod from, DexMethod to) { assert from != to; - originalMethodSignatures.put(from, from); - extraOriginalMethodSignatures.put(to, from); + methodMap.put(from, from); + extraNewMethodSignatures.put(from, to); } @Override - public InterfaceProcessorNestedGraphLens build( - DexItemFactory dexItemFactory, GraphLens previousLens) { - if (fieldMap.isEmpty() - && originalMethodSignatures.isEmpty() - && extraOriginalMethodSignatures.isEmpty()) { + public InterfaceProcessorNestedGraphLens build(AppView<?> appView) { + if (fieldMap.isEmpty() && methodMap.isEmpty() && extraNewMethodSignatures.isEmpty()) { return null; } return new InterfaceProcessorNestedGraphLens( - typeMap, - methodMap, - fieldMap, - originalMethodSignatures, - extraOriginalMethodSignatures, - previousLens, - dexItemFactory); + appView, fieldMap, methodMap, typeMap, extraNewMethodSignatures); } } }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java index d54264c..a264d65 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -575,7 +575,7 @@ true); newMethod.copyMetadata(encodedMethod); forcefullyMovedLambdaMethodConsumer.acceptForcefullyMovedLambdaMethod( - encodedMethod.method, callTarget); + encodedMethod.getReference(), callTarget); DexEncodedMethod.setDebugInfoWithFakeThisParameter( newMethod.getCode(), callTarget.getArity(), appView); @@ -659,7 +659,7 @@ true); newMethod.copyMetadata(encodedMethod); forcefullyMovedLambdaMethodConsumer.acceptForcefullyMovedLambdaMethod( - encodedMethod.method, callTarget); + encodedMethod.getReference(), callTarget); return newMethod; }); if (replacement != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/RecordCfMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/RecordCfMethods.java new file mode 100644 index 0000000..85a7982 --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/desugar/RecordCfMethods.java
@@ -0,0 +1,454 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// *********************************************************************************** +// GENERATED FILE. DO NOT EDIT! See GenerateRecordMethods.java. +// *********************************************************************************** + +package com.android.tools.r8.ir.desugar; + +import com.android.tools.r8.cf.code.CfArithmeticBinop; +import com.android.tools.r8.cf.code.CfArrayLength; +import com.android.tools.r8.cf.code.CfArrayLoad; +import com.android.tools.r8.cf.code.CfCheckCast; +import com.android.tools.r8.cf.code.CfConstNumber; +import com.android.tools.r8.cf.code.CfConstString; +import com.android.tools.r8.cf.code.CfFrame; +import com.android.tools.r8.cf.code.CfFrame.FrameType; +import com.android.tools.r8.cf.code.CfGoto; +import com.android.tools.r8.cf.code.CfIf; +import com.android.tools.r8.cf.code.CfIfCmp; +import com.android.tools.r8.cf.code.CfIinc; +import com.android.tools.r8.cf.code.CfInvoke; +import com.android.tools.r8.cf.code.CfLabel; +import com.android.tools.r8.cf.code.CfLoad; +import com.android.tools.r8.cf.code.CfNew; +import com.android.tools.r8.cf.code.CfNewArray; +import com.android.tools.r8.cf.code.CfReturn; +import com.android.tools.r8.cf.code.CfStackInstruction; +import com.android.tools.r8.cf.code.CfStore; +import com.android.tools.r8.graph.CfCode; +import com.android.tools.r8.graph.DexItemFactory; +import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.ir.code.If; +import com.android.tools.r8.ir.code.MemberType; +import com.android.tools.r8.ir.code.NumericType; +import com.android.tools.r8.ir.code.ValueType; +import com.android.tools.r8.utils.InternalOptions; +import com.google.common.collect.ImmutableList; +import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap; +import java.util.ArrayDeque; +import java.util.Arrays; + +public final class RecordCfMethods { + + public static void registerSynthesizedCodeReferences(DexItemFactory factory) { + factory.createSynthesizedType( + "Lcom/android/tools/r8/desugar/records/RecordMethods$RecordStub;"); + factory.createSynthesizedType("Ljava/lang/Record;"); + factory.createSynthesizedType("Ljava/util/Arrays;"); + factory.createSynthesizedType("[Ljava/lang/Object;"); + factory.createSynthesizedType("[Ljava/lang/String;"); + } + + public static CfCode RecordMethods_equals(InternalOptions options, DexMethod method) { + CfLabel label0 = new CfLabel(); + CfLabel label1 = new CfLabel(); + CfLabel label2 = new CfLabel(); + CfLabel label3 = new CfLabel(); + CfLabel label4 = new CfLabel(); + CfLabel label5 = new CfLabel(); + return new CfCode( + method.holder, + 2, + 2, + ImmutableList.of( + label0, + new CfLoad(ValueType.OBJECT, 0), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.objectType, + options.itemFactory.createProto(options.itemFactory.classType), + options.itemFactory.createString("getClass")), + false), + new CfLoad(ValueType.OBJECT, 1), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.objectType, + options.itemFactory.createProto(options.itemFactory.classType), + options.itemFactory.createString("getClass")), + false), + new CfIfCmp(If.Type.NE, ValueType.OBJECT, label3), + new CfLoad(ValueType.OBJECT, 1), + new CfCheckCast(options.itemFactory.createType("Ljava/lang/Record;")), + label1, + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.createType("Ljava/lang/Record;"), + options.itemFactory.createProto( + options.itemFactory.createType("[Ljava/lang/Object;")), + options.itemFactory.createString("$record$getFieldsAsObjects")), + false), + new CfLoad(ValueType.OBJECT, 0), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.createType("Ljava/lang/Record;"), + options.itemFactory.createProto( + options.itemFactory.createType("[Ljava/lang/Object;")), + options.itemFactory.createString("$record$getFieldsAsObjects")), + false), + label2, + new CfInvoke( + 184, + options.itemFactory.createMethod( + options.itemFactory.createType("Ljava/util/Arrays;"), + options.itemFactory.createProto( + options.itemFactory.booleanType, + options.itemFactory.createType("[Ljava/lang/Object;"), + options.itemFactory.createType("[Ljava/lang/Object;")), + options.itemFactory.createString("equals")), + false), + new CfIf(If.Type.EQ, ValueType.INT, label3), + new CfConstNumber(1, ValueType.INT), + new CfGoto(label4), + label3, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType( + "Lcom/android/tools/r8/desugar/records/RecordMethods$RecordStub;")), + FrameType.initialized(options.itemFactory.objectType) + }), + new ArrayDeque<>(Arrays.asList())), + new CfConstNumber(0, ValueType.INT), + label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType( + "Lcom/android/tools/r8/desugar/records/RecordMethods$RecordStub;")), + FrameType.initialized(options.itemFactory.objectType) + }), + new ArrayDeque<>( + Arrays.asList(FrameType.initialized(options.itemFactory.intType)))), + new CfReturn(ValueType.INT), + label5), + ImmutableList.of(), + ImmutableList.of()); + } + + public static CfCode RecordMethods_hashCode(InternalOptions options, DexMethod method) { + CfLabel label0 = new CfLabel(); + CfLabel label1 = new CfLabel(); + CfLabel label2 = new CfLabel(); + CfLabel label3 = new CfLabel(); + return new CfCode( + method.holder, + 2, + 1, + ImmutableList.of( + label0, + new CfConstNumber(31, ValueType.INT), + new CfLoad(ValueType.OBJECT, 0), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.createType("Ljava/lang/Record;"), + options.itemFactory.createProto( + options.itemFactory.createType("[Ljava/lang/Object;")), + options.itemFactory.createString("$record$getFieldsAsObjects")), + false), + new CfInvoke( + 184, + options.itemFactory.createMethod( + options.itemFactory.createType("Ljava/util/Arrays;"), + options.itemFactory.createProto( + options.itemFactory.intType, + options.itemFactory.createType("[Ljava/lang/Object;")), + options.itemFactory.createString("hashCode")), + false), + new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.INT), + new CfLoad(ValueType.OBJECT, 0), + label1, + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.objectType, + options.itemFactory.createProto(options.itemFactory.classType), + options.itemFactory.createString("getClass")), + false), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.objectType, + options.itemFactory.createProto(options.itemFactory.intType), + options.itemFactory.createString("hashCode")), + false), + new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.INT), + label2, + new CfReturn(ValueType.INT), + label3), + ImmutableList.of(), + ImmutableList.of()); + } + + public static CfCode RecordMethods_toString(InternalOptions options, DexMethod method) { + CfLabel label0 = new CfLabel(); + CfLabel label1 = new CfLabel(); + CfLabel label2 = new CfLabel(); + CfLabel label3 = new CfLabel(); + CfLabel label4 = new CfLabel(); + CfLabel label5 = new CfLabel(); + CfLabel label6 = new CfLabel(); + CfLabel label7 = new CfLabel(); + CfLabel label8 = new CfLabel(); + CfLabel label9 = new CfLabel(); + CfLabel label10 = new CfLabel(); + CfLabel label11 = new CfLabel(); + CfLabel label12 = new CfLabel(); + CfLabel label13 = new CfLabel(); + CfLabel label14 = new CfLabel(); + return new CfCode( + method.holder, + 3, + 7, + ImmutableList.of( + label0, + new CfLoad(ValueType.OBJECT, 2), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.stringType, + options.itemFactory.createProto(options.itemFactory.booleanType), + options.itemFactory.createString("isEmpty")), + false), + new CfIf(If.Type.EQ, ValueType.INT, label1), + new CfConstNumber(0, ValueType.INT), + new CfNewArray(options.itemFactory.createType("[Ljava/lang/String;")), + new CfGoto(label2), + label1, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType( + "Lcom/android/tools/r8/desugar/records/RecordMethods$RecordStub;")), + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.stringType) + }), + new ArrayDeque<>(Arrays.asList())), + new CfLoad(ValueType.OBJECT, 2), + new CfConstString(options.itemFactory.createString(";")), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.stringType, + options.itemFactory.createProto( + options.itemFactory.createType("[Ljava/lang/String;"), + options.itemFactory.stringType), + options.itemFactory.createString("split")), + false), + label2, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType( + "Lcom/android/tools/r8/desugar/records/RecordMethods$RecordStub;")), + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.stringType) + }), + new ArrayDeque<>( + Arrays.asList( + FrameType.initialized( + options.itemFactory.createType("[Ljava/lang/String;"))))), + new CfStore(ValueType.OBJECT, 3), + label3, + new CfLoad(ValueType.OBJECT, 0), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.createType("Ljava/lang/Record;"), + options.itemFactory.createProto( + options.itemFactory.createType("[Ljava/lang/Object;")), + options.itemFactory.createString("$record$getFieldsAsObjects")), + false), + new CfStore(ValueType.OBJECT, 4), + label4, + new CfNew(options.itemFactory.stringBuilderType), + new CfStackInstruction(CfStackInstruction.Opcode.Dup), + new CfInvoke( + 183, + options.itemFactory.createMethod( + options.itemFactory.stringBuilderType, + options.itemFactory.createProto(options.itemFactory.voidType), + options.itemFactory.createString("<init>")), + false), + new CfStore(ValueType.OBJECT, 5), + label5, + new CfLoad(ValueType.OBJECT, 5), + new CfLoad(ValueType.OBJECT, 1), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.stringBuilderType, + options.itemFactory.createProto( + options.itemFactory.stringBuilderType, options.itemFactory.stringType), + options.itemFactory.createString("append")), + false), + new CfConstString(options.itemFactory.createString("[")), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.stringBuilderType, + options.itemFactory.createProto( + options.itemFactory.stringBuilderType, options.itemFactory.stringType), + options.itemFactory.createString("append")), + false), + new CfStackInstruction(CfStackInstruction.Opcode.Pop), + label6, + new CfConstNumber(0, ValueType.INT), + new CfStore(ValueType.INT, 6), + label7, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 4, 5, 6}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType( + "Lcom/android/tools/r8/desugar/records/RecordMethods$RecordStub;")), + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/String;")), + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/Object;")), + FrameType.initialized(options.itemFactory.stringBuilderType), + FrameType.initialized(options.itemFactory.intType) + }), + new ArrayDeque<>(Arrays.asList())), + new CfLoad(ValueType.INT, 6), + new CfLoad(ValueType.OBJECT, 3), + new CfArrayLength(), + new CfIfCmp(If.Type.GE, ValueType.INT, label12), + label8, + new CfLoad(ValueType.OBJECT, 5), + new CfLoad(ValueType.OBJECT, 3), + new CfLoad(ValueType.INT, 6), + new CfArrayLoad(MemberType.OBJECT), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.stringBuilderType, + options.itemFactory.createProto( + options.itemFactory.stringBuilderType, options.itemFactory.stringType), + options.itemFactory.createString("append")), + false), + new CfConstString(options.itemFactory.createString("=")), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.stringBuilderType, + options.itemFactory.createProto( + options.itemFactory.stringBuilderType, options.itemFactory.stringType), + options.itemFactory.createString("append")), + false), + new CfLoad(ValueType.OBJECT, 4), + new CfLoad(ValueType.INT, 6), + new CfArrayLoad(MemberType.OBJECT), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.stringBuilderType, + options.itemFactory.createProto( + options.itemFactory.stringBuilderType, options.itemFactory.objectType), + options.itemFactory.createString("append")), + false), + new CfStackInstruction(CfStackInstruction.Opcode.Pop), + label9, + new CfLoad(ValueType.INT, 6), + new CfLoad(ValueType.OBJECT, 3), + new CfArrayLength(), + new CfConstNumber(1, ValueType.INT), + new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT), + new CfIfCmp(If.Type.EQ, ValueType.INT, label11), + label10, + new CfLoad(ValueType.OBJECT, 5), + new CfConstString(options.itemFactory.createString(", ")), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.stringBuilderType, + options.itemFactory.createProto( + options.itemFactory.stringBuilderType, options.itemFactory.stringType), + options.itemFactory.createString("append")), + false), + new CfStackInstruction(CfStackInstruction.Opcode.Pop), + label11, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 4, 5, 6}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType( + "Lcom/android/tools/r8/desugar/records/RecordMethods$RecordStub;")), + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/String;")), + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/Object;")), + FrameType.initialized(options.itemFactory.stringBuilderType), + FrameType.initialized(options.itemFactory.intType) + }), + new ArrayDeque<>(Arrays.asList())), + new CfIinc(6, 1), + new CfGoto(label7), + label12, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3, 4, 5}, + new FrameType[] { + FrameType.initialized( + options.itemFactory.createType( + "Lcom/android/tools/r8/desugar/records/RecordMethods$RecordStub;")), + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.stringType), + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/String;")), + FrameType.initialized(options.itemFactory.createType("[Ljava/lang/Object;")), + FrameType.initialized(options.itemFactory.stringBuilderType) + }), + new ArrayDeque<>(Arrays.asList())), + new CfLoad(ValueType.OBJECT, 5), + new CfConstString(options.itemFactory.createString("]")), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.stringBuilderType, + options.itemFactory.createProto( + options.itemFactory.stringBuilderType, options.itemFactory.stringType), + options.itemFactory.createString("append")), + false), + new CfStackInstruction(CfStackInstruction.Opcode.Pop), + label13, + new CfLoad(ValueType.OBJECT, 5), + new CfInvoke( + 182, + options.itemFactory.createMethod( + options.itemFactory.stringBuilderType, + options.itemFactory.createProto(options.itemFactory.stringType), + options.itemFactory.createString("toString")), + false), + new CfReturn(ValueType.OBJECT), + label14), + ImmutableList.of(), + ImmutableList.of()); + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/RecordDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/RecordDesugaringEventConsumer.java index 19d9ae3..61eb249 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/RecordDesugaringEventConsumer.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/RecordDesugaringEventConsumer.java
@@ -5,8 +5,11 @@ package com.android.tools.r8.ir.desugar; import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.ProgramMethod; public interface RecordDesugaringEventConsumer { void acceptRecordClass(DexProgramClass recordClass); + + void acceptRecordMethod(ProgramMethod method); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/RecordRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/RecordRewriter.java index 67e2c90..469f119 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/RecordRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/RecordRewriter.java
@@ -4,50 +4,78 @@ package com.android.tools.r8.ir.desugar; -import com.android.tools.r8.cf.code.CfConstNull; -import com.android.tools.r8.cf.code.CfConstNumber; +import com.android.tools.r8.cf.code.CfConstString; import com.android.tools.r8.cf.code.CfFieldInstruction; import com.android.tools.r8.cf.code.CfInstruction; import com.android.tools.r8.cf.code.CfInvoke; -import com.android.tools.r8.cf.code.CfStackInstruction; +import com.android.tools.r8.cf.code.CfInvokeDynamic; import com.android.tools.r8.cf.code.CfTypeInstruction; import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext; import com.android.tools.r8.dex.Constants; import com.android.tools.r8.errors.CompilationError; +import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.CfCode; import com.android.tools.r8.graph.DexAnnotationSet; +import com.android.tools.r8.graph.DexCallSite; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.DexMethodHandle; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexProto; +import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexValue.DexValueMethodHandle; +import com.android.tools.r8.graph.DexValue.DexValueString; +import com.android.tools.r8.graph.DexValue.DexValueType; import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature; import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.ParameterAnnotationsList; import com.android.tools.r8.graph.ProgramMethod; -import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.synthetic.CallObjectInitCfCodeProvider; +import com.android.tools.r8.ir.synthetic.RecordGetFieldsAsObjectsCfCodeProvider; +import com.android.tools.r8.naming.dexitembasedstring.ClassNameComputationInfo; import com.android.tools.r8.synthesis.SyntheticNaming; +import com.android.tools.r8.utils.InternalOptions; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.List; +import java.util.function.BiFunction; +import org.objectweb.asm.Opcodes; public class RecordRewriter implements CfInstructionDesugaring, CfClassDesugaring { private final AppView<?> appView; private final DexItemFactory factory; + private final DexProto recordToStringHelperProto; + private final DexProto recordEqualsHelperProto; + private final DexProto recordHashCodeHelperProto; + + public static final String GET_FIELDS_AS_OBJECTS_METHOD_NAME = "$record$getFieldsAsObjects"; public static RecordRewriter create(AppView<?> appView) { return appView.options().shouldDesugarRecords() ? new RecordRewriter(appView) : null; } + public static void registerSynthesizedCodeReferences(DexItemFactory factory) { + RecordCfMethods.registerSynthesizedCodeReferences(factory); + RecordGetFieldsAsObjectsCfCodeProvider.registerSynthesizedCodeReferences(factory); + } + private RecordRewriter(AppView<?> appView) { this.appView = appView; factory = appView.dexItemFactory(); + recordToStringHelperProto = + factory.createProto( + factory.stringType, factory.recordType, factory.stringType, factory.stringType); + recordEqualsHelperProto = + factory.createProto(factory.booleanType, factory.recordType, factory.objectType); + recordHashCodeHelperProto = factory.createProto(factory.intType, factory.recordType); } public void scan( @@ -97,41 +125,168 @@ CfInstructionDesugaringEventConsumer eventConsumer, ProgramMethod context, MethodProcessingContext methodProcessingContext) { - - // TODO(b/179146128): This is a temporary work-around to test desugaring of records - // without rewriting the record invoke-custom. This should be removed when the record support - // is complete. - if (instruction.isInvokeDynamic() - && context.getHolder().superType == factory.recordType - && (context.getReference().match(factory.recordMembers.toString) - || context.getReference().match(factory.recordMembers.hashCode) - || context.getReference().match(factory.recordMembers.equals))) { - requiresRecordClass(eventConsumer); - CfInstruction constant = - context.getReference().match(factory.recordMembers.toString) - ? new CfConstNull() - : new CfConstNumber(0, ValueType.INT); - return ImmutableList.of(new CfStackInstruction(CfStackInstruction.Opcode.Pop), constant); - } - - CfInstruction desugaredInstruction = desugarInstruction(instruction, context); - return desugaredInstruction == null ? null : Collections.singletonList(desugaredInstruction); - } - - private CfInstruction desugarInstruction(CfInstruction instruction, ProgramMethod context) { assert !instruction.isInitClass(); - // TODO(b/179146128): Rewrite record invoke-dynamic here. + if (instruction.isInvokeDynamic() && needsDesugaring(instruction.asInvokeDynamic(), context)) { + return desugarInvokeDynamicOnRecord( + instruction.asInvokeDynamic(), context, eventConsumer, methodProcessingContext); + } if (instruction.isInvoke()) { CfInvoke cfInvoke = instruction.asInvoke(); DexMethod newMethod = rewriteMethod(cfInvoke.getMethod(), cfInvoke.isInvokeSuper(context.getHolderType())); if (newMethod != cfInvoke.getMethod()) { - return new CfInvoke(cfInvoke.getOpcode(), newMethod, cfInvoke.isInterface()); + return Collections.singletonList( + new CfInvoke(cfInvoke.getOpcode(), newMethod, cfInvoke.isInterface())); } } return null; } + public List<CfInstruction> desugarInvokeDynamicOnRecord( + CfInvokeDynamic invokeDynamic, + ProgramMethod context, + CfInstructionDesugaringEventConsumer eventConsumer, + MethodProcessingContext methodProcessingContext) { + assert needsDesugaring(invokeDynamic, context); + DexCallSite callSite = invokeDynamic.getCallSite(); + DexValueType recordValueType = callSite.bootstrapArgs.get(0).asDexValueType(); + DexValueString valueString = callSite.bootstrapArgs.get(1).asDexValueString(); + DexString fieldNames = valueString.getValue(); + DexField[] fields = new DexField[callSite.bootstrapArgs.size() - 2]; + for (int i = 2; i < callSite.bootstrapArgs.size(); i++) { + DexValueMethodHandle handle = callSite.bootstrapArgs.get(i).asDexValueMethodHandle(); + fields[i - 2] = handle.value.member.asDexField(); + } + DexProgramClass recordClass = + appView.definitionFor(recordValueType.getValue()).asProgramClass(); + if (callSite.methodName == factory.toStringMethodName) { + DexString simpleName = + ClassNameComputationInfo.ClassNameMapping.SIMPLE_NAME.map( + recordValueType.getValue().toDescriptorString(), context.getHolder(), factory); + return desugarInvokeRecordToString( + recordClass, fieldNames, fields, simpleName, eventConsumer, methodProcessingContext); + } + if (callSite.methodName == factory.hashCodeMethodName) { + return desugarInvokeRecordHashCode( + recordClass, fields, eventConsumer, methodProcessingContext); + } + if (callSite.methodName == factory.equalsMethodName) { + return desugarInvokeRecordEquals(recordClass, fields, eventConsumer, methodProcessingContext); + } + throw new Unreachable("Invoke dynamic needs record desugaring but could not be desugared."); + } + + private ProgramMethod synthesizeGetFieldsAsObjectsMethod( + DexProgramClass clazz, DexField[] fields, DexMethod method) { + MethodAccessFlags methodAccessFlags = + MethodAccessFlags.fromSharedAccessFlags( + Constants.ACC_SYNTHETIC | Constants.ACC_PUBLIC, false); + DexEncodedMethod encodedMethod = + new DexEncodedMethod( + method, + methodAccessFlags, + MethodTypeSignature.noSignature(), + DexAnnotationSet.empty(), + ParameterAnnotationsList.empty(), + null, + true); + encodedMethod.setCode( + new RecordGetFieldsAsObjectsCfCodeProvider(appView, factory.recordTagType, fields) + .generateCfCode(), + appView); + return new ProgramMethod(clazz, encodedMethod); + } + + private void ensureGetFieldsAsObjects( + DexProgramClass clazz, DexField[] fields, RecordDesugaringEventConsumer eventConsumer) { + DexMethod method = getFieldsAsObjectsMethod(clazz.type); + synchronized (clazz.getMethodCollection()) { + ProgramMethod getFieldsAsObjects = clazz.lookupProgramMethod(method); + if (getFieldsAsObjects == null) { + getFieldsAsObjects = synthesizeGetFieldsAsObjectsMethod(clazz, fields, method); + clazz.addVirtualMethod(getFieldsAsObjects.getDefinition()); + if (eventConsumer != null) { + eventConsumer.acceptRecordMethod(getFieldsAsObjects); + } + } + } + } + + private DexMethod getFieldsAsObjectsMethod(DexType holder) { + return factory.createMethod( + holder, factory.createProto(factory.objectArrayType), GET_FIELDS_AS_OBJECTS_METHOD_NAME); + } + + private ProgramMethod synthesizeRecordHelper( + DexProto helperProto, + BiFunction<InternalOptions, DexMethod, CfCode> codeGenerator, + MethodProcessingContext methodProcessingContext) { + return appView + .getSyntheticItems() + .createMethod( + SyntheticNaming.SyntheticKind.RECORD_HELPER, + methodProcessingContext.createUniqueContext(), + factory, + builder -> + builder + .setProto(helperProto) + .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) + .setCode(methodSig -> codeGenerator.apply(appView.options(), methodSig))); + } + + private List<CfInstruction> desugarInvokeRecordHashCode( + DexProgramClass recordClass, + DexField[] fields, + CfInstructionDesugaringEventConsumer eventConsumer, + MethodProcessingContext methodProcessingContext) { + ensureGetFieldsAsObjects(recordClass, fields, eventConsumer); + ProgramMethod programMethod = + synthesizeRecordHelper( + recordHashCodeHelperProto, + RecordCfMethods::RecordMethods_hashCode, + methodProcessingContext); + eventConsumer.acceptRecordMethod(programMethod); + return ImmutableList.of( + new CfInvoke(Opcodes.INVOKESTATIC, programMethod.getReference(), false)); + } + + private List<CfInstruction> desugarInvokeRecordEquals( + DexProgramClass recordClass, + DexField[] fields, + CfInstructionDesugaringEventConsumer eventConsumer, + MethodProcessingContext methodProcessingContext) { + ensureGetFieldsAsObjects(recordClass, fields, eventConsumer); + ProgramMethod programMethod = + synthesizeRecordHelper( + recordEqualsHelperProto, + RecordCfMethods::RecordMethods_equals, + methodProcessingContext); + eventConsumer.acceptRecordMethod(programMethod); + return ImmutableList.of( + new CfInvoke(Opcodes.INVOKESTATIC, programMethod.getReference(), false)); + } + + private List<CfInstruction> desugarInvokeRecordToString( + DexProgramClass recordClass, + DexString fieldNames, + DexField[] fields, + DexString simpleName, + CfInstructionDesugaringEventConsumer eventConsumer, + MethodProcessingContext methodProcessingContext) { + ensureGetFieldsAsObjects(recordClass, fields, eventConsumer); + ArrayList<CfInstruction> instructions = new ArrayList<>(); + instructions.add(new CfConstString(simpleName)); + instructions.add(new CfConstString(fieldNames)); + ProgramMethod programMethod = + synthesizeRecordHelper( + recordToStringHelperProto, + RecordCfMethods::RecordMethods_toString, + methodProcessingContext); + eventConsumer.acceptRecordMethod(programMethod); + instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, programMethod.getReference(), false)); + return instructions; + } + @Override public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) { assert !instruction.isInitClass(); @@ -161,7 +316,6 @@ @Override public boolean needsDesugaring(DexProgramClass clazz) { - assert clazz.isRecord() || clazz.superType != factory.recordType; return clazz.isRecord(); } @@ -210,14 +364,85 @@ return rewriteMethod(method, isSuper) != method; } + private boolean needsDesugaring(CfInvokeDynamic invokeDynamic, ProgramMethod context) { + DexCallSite callSite = invokeDynamic.getCallSite(); + // 1. Validates this is an invoke-static to ObjectMethods#bootstrap. + DexMethodHandle bootstrapMethod = callSite.bootstrapMethod; + if (!bootstrapMethod.type.isInvokeStatic()) { + return false; + } + if (bootstrapMethod.member != factory.objectMethodsMembers.bootstrap) { + return false; + } + // From there on we assume in the assertions that the invoke to the library method is + // well-formed. If the invoke is not well formed assertions will fail but the execution is + // correct. + if (bootstrapMethod.isInterface) { + assert false + : "Invoke-dynamic invoking non interface method ObjectMethods#bootstrap as an interface" + + " method."; + return false; + } + // 2. Validate the bootstrapArgs include the record type, the instance field names and + // the corresponding instance getters. + if (callSite.bootstrapArgs.size() < 2) { + assert false + : "Invoke-dynamic invoking method ObjectMethods#bootstrap with less than 2 parameters."; + return false; + } + DexValueType recordType = callSite.bootstrapArgs.get(0).asDexValueType(); + if (recordType == null) { + assert false : "Invoke-dynamic invoking method ObjectMethods#bootstrap with an invalid type."; + return false; + } + DexClass recordClass = appView.definitionFor(recordType.getValue()); + if (recordClass == null || recordClass.isNotProgramClass()) { + return false; + } + DexValueString valueString = callSite.bootstrapArgs.get(1).asDexValueString(); + if (valueString == null) { + assert false + : "Invoke-dynamic invoking method ObjectMethods#bootstrap with invalid field names."; + return false; + } + DexString fieldNames = valueString.getValue(); + assert fieldNames.toString().isEmpty() + || (fieldNames.toString().split(";").length == callSite.bootstrapArgs.size() - 2); + assert recordClass.instanceFields().size() == callSite.bootstrapArgs.size() - 2; + for (int i = 2; i < callSite.bootstrapArgs.size(); i++) { + DexValueMethodHandle handle = callSite.bootstrapArgs.get(i).asDexValueMethodHandle(); + if (handle == null + || !handle.value.type.isInstanceGet() + || !handle.value.member.isDexField()) { + assert false + : "Invoke-dynamic invoking method ObjectMethods#bootstrap with invalid getters."; + return false; + } + } + // 3. Create the invoke-record instruction. + if (callSite.methodName == factory.toStringMethodName) { + assert callSite.methodProto == factory.createProto(factory.stringType, recordClass.getType()); + return true; + } + if (callSite.methodName == factory.hashCodeMethodName) { + assert callSite.methodProto == factory.createProto(factory.intType, recordClass.getType()); + return true; + } + if (callSite.methodName == factory.equalsMethodName) { + assert callSite.methodProto + == factory.createProto(factory.booleanType, recordClass.getType(), factory.objectType); + return true; + } + return false; + } + @SuppressWarnings("ConstantConditions") private DexMethod rewriteMethod(DexMethod method, boolean isSuper) { - if (method.holder != factory.recordType || method.isInstanceInitializer(factory)) { + if (!(method == factory.recordMembers.equals + || method == factory.recordMembers.hashCode + || method == factory.recordMembers.toString)) { return method; } - assert method == factory.recordMembers.equals - || method == factory.recordMembers.hashCode - || method == factory.recordMembers.toString; if (isSuper) { // TODO(b/179146128): Support rewriting invoke-super to a Record method. throw new CompilationError("Rewrite invoke-super to abstract method error."); @@ -234,22 +459,61 @@ private DexProgramClass synthesizeR8Record() { DexItemFactory factory = appView.dexItemFactory(); + DexClass r8RecordClass = + appView.appInfo().definitionForWithoutExistenceAssert(factory.recordTagType); + if (r8RecordClass != null && r8RecordClass.isProgramClass()) { + appView + .options() + .reporter + .error( + "D8/R8 is compiling a mix of desugared and non desugared input using" + + " java.lang.Record, but the application reader did not import correctly " + + factory.recordTagType.toString()); + } DexClass recordClass = appView.appInfo().definitionForWithoutExistenceAssert(factory.recordType); if (recordClass != null && recordClass.isProgramClass()) { return null; } - assert recordClass == null || recordClass.isLibraryClass(); + return synchronizedSynthesizeR8Record(); + } + + private synchronized DexProgramClass synchronizedSynthesizeR8Record() { + DexItemFactory factory = appView.dexItemFactory(); + DexClass recordClass = + appView.appInfo().definitionForWithoutExistenceAssert(factory.recordType); + if (recordClass != null && recordClass.isProgramClass()) { + return null; + } DexEncodedMethod init = synthesizeRecordInitMethod(); - // TODO(b/179146128): We may want to remove here the class from the library classes if present - // in cf to cf. + DexEncodedMethod abstractGetFieldsAsObjectsMethod = + synthesizeAbstractGetFieldsAsObjectsMethod(); return appView .getSyntheticItems() .createFixedClassFromType( SyntheticNaming.SyntheticKind.RECORD_TAG, factory.recordType, factory, - builder -> builder.setAbstract().setDirectMethods(Collections.singletonList(init))); + builder -> + builder + .setAbstract() + .setVirtualMethods(ImmutableList.of(abstractGetFieldsAsObjectsMethod)) + .setDirectMethods(ImmutableList.of(init))); + } + + private DexEncodedMethod synthesizeAbstractGetFieldsAsObjectsMethod() { + MethodAccessFlags methodAccessFlags = + MethodAccessFlags.fromSharedAccessFlags( + Constants.ACC_SYNTHETIC | Constants.ACC_PUBLIC | Constants.ACC_ABSTRACT, false); + DexMethod fieldsAsObjectsMethod = getFieldsAsObjectsMethod(factory.recordType); + return new DexEncodedMethod( + fieldsAsObjectsMethod, + methodAccessFlags, + MethodTypeSignature.noSignature(), + DexAnnotationSet.empty(), + ParameterAnnotationsList.empty(), + null, + true); } private DexEncodedMethod synthesizeRecordInitMethod() { @@ -266,7 +530,7 @@ null, true); init.setCode( - new CallObjectInitCfCodeProvider(appView, factory.r8RecordType).generateCfCode(), appView); + new CallObjectInitCfCodeProvider(appView, factory.recordTagType).generateCfCode(), appView); return init; } }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java index b7b0db0..3f7a705 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
@@ -2162,6 +2162,113 @@ ImmutableList.of()); } + public static CfCode IntegerMethods_parseIntSubsequenceWithRadixDalvik( + InternalOptions options, DexMethod method) { + CfLabel label0 = new CfLabel(); + CfLabel label1 = new CfLabel(); + CfLabel label2 = new CfLabel(); + CfLabel label3 = new CfLabel(); + CfLabel label4 = new CfLabel(); + CfLabel label5 = new CfLabel(); + return new CfCode( + method.holder, + 3, + 4, + ImmutableList.of( + label0, + new CfLoad(ValueType.INT, 2), + new CfLoad(ValueType.INT, 1), + new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT), + new CfConstNumber(2, ValueType.INT), + new CfIfCmp(If.Type.LT, ValueType.INT, label4), + new CfLoad(ValueType.OBJECT, 0), + new CfLoad(ValueType.INT, 1), + label1, + new CfInvoke( + 185, + options.itemFactory.createMethod( + options.itemFactory.charSequenceType, + options.itemFactory.createProto( + options.itemFactory.charType, options.itemFactory.intType), + options.itemFactory.createString("charAt")), + true), + new CfConstNumber(43, ValueType.INT), + new CfIfCmp(If.Type.NE, ValueType.INT, label4), + new CfLoad(ValueType.OBJECT, 0), + new CfLoad(ValueType.INT, 1), + new CfConstNumber(1, ValueType.INT), + new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.INT), + label2, + new CfInvoke( + 185, + options.itemFactory.createMethod( + options.itemFactory.charSequenceType, + options.itemFactory.createProto( + options.itemFactory.charType, options.itemFactory.intType), + options.itemFactory.createString("charAt")), + true), + new CfLoad(ValueType.INT, 3), + new CfInvoke( + 184, + options.itemFactory.createMethod( + options.itemFactory.boxedCharType, + options.itemFactory.createProto( + options.itemFactory.intType, + options.itemFactory.charType, + options.itemFactory.intType), + options.itemFactory.createString("digit")), + false), + new CfIf(If.Type.LT, ValueType.INT, label4), + label3, + new CfIinc(1, 1), + label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + new ArrayDeque<>(Arrays.asList())), + new CfLoad(ValueType.OBJECT, 0), + new CfLoad(ValueType.INT, 1), + new CfLoad(ValueType.INT, 2), + new CfInvoke( + 185, + options.itemFactory.createMethod( + options.itemFactory.charSequenceType, + options.itemFactory.createProto( + options.itemFactory.charSequenceType, + options.itemFactory.intType, + options.itemFactory.intType), + options.itemFactory.createString("subSequence")), + true), + new CfInvoke( + 185, + options.itemFactory.createMethod( + options.itemFactory.charSequenceType, + options.itemFactory.createProto(options.itemFactory.stringType), + options.itemFactory.createString("toString")), + true), + new CfLoad(ValueType.INT, 3), + new CfInvoke( + 184, + options.itemFactory.createMethod( + options.itemFactory.createType("Ljava/lang/Integer;"), + options.itemFactory.createProto( + options.itemFactory.intType, + options.itemFactory.stringType, + options.itemFactory.intType), + options.itemFactory.createString("parseInt")), + false), + new CfReturn(ValueType.INT), + label5), + ImmutableList.of(), + ImmutableList.of()); + } + public static CfCode IntegerMethods_parseUnsignedInt(InternalOptions options, DexMethod method) { CfLabel label0 = new CfLabel(); CfLabel label1 = new CfLabel(); @@ -2737,6 +2844,113 @@ ImmutableList.of()); } + public static CfCode LongMethods_parseLongSubsequenceWithRadixDalvik( + InternalOptions options, DexMethod method) { + CfLabel label0 = new CfLabel(); + CfLabel label1 = new CfLabel(); + CfLabel label2 = new CfLabel(); + CfLabel label3 = new CfLabel(); + CfLabel label4 = new CfLabel(); + CfLabel label5 = new CfLabel(); + return new CfCode( + method.holder, + 3, + 4, + ImmutableList.of( + label0, + new CfLoad(ValueType.INT, 2), + new CfLoad(ValueType.INT, 1), + new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT), + new CfConstNumber(2, ValueType.INT), + new CfIfCmp(If.Type.LT, ValueType.INT, label4), + new CfLoad(ValueType.OBJECT, 0), + new CfLoad(ValueType.INT, 1), + label1, + new CfInvoke( + 185, + options.itemFactory.createMethod( + options.itemFactory.charSequenceType, + options.itemFactory.createProto( + options.itemFactory.charType, options.itemFactory.intType), + options.itemFactory.createString("charAt")), + true), + new CfConstNumber(43, ValueType.INT), + new CfIfCmp(If.Type.NE, ValueType.INT, label4), + new CfLoad(ValueType.OBJECT, 0), + new CfLoad(ValueType.INT, 1), + new CfConstNumber(1, ValueType.INT), + new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.INT), + label2, + new CfInvoke( + 185, + options.itemFactory.createMethod( + options.itemFactory.charSequenceType, + options.itemFactory.createProto( + options.itemFactory.charType, options.itemFactory.intType), + options.itemFactory.createString("charAt")), + true), + new CfLoad(ValueType.INT, 3), + new CfInvoke( + 184, + options.itemFactory.createMethod( + options.itemFactory.boxedCharType, + options.itemFactory.createProto( + options.itemFactory.intType, + options.itemFactory.charType, + options.itemFactory.intType), + options.itemFactory.createString("digit")), + false), + new CfIf(If.Type.LT, ValueType.INT, label4), + label3, + new CfIinc(1, 1), + label4, + new CfFrame( + new Int2ReferenceAVLTreeMap<>( + new int[] {0, 1, 2, 3}, + new FrameType[] { + FrameType.initialized(options.itemFactory.charSequenceType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType), + FrameType.initialized(options.itemFactory.intType) + }), + new ArrayDeque<>(Arrays.asList())), + new CfLoad(ValueType.OBJECT, 0), + new CfLoad(ValueType.INT, 1), + new CfLoad(ValueType.INT, 2), + new CfInvoke( + 185, + options.itemFactory.createMethod( + options.itemFactory.charSequenceType, + options.itemFactory.createProto( + options.itemFactory.charSequenceType, + options.itemFactory.intType, + options.itemFactory.intType), + options.itemFactory.createString("subSequence")), + true), + new CfInvoke( + 185, + options.itemFactory.createMethod( + options.itemFactory.charSequenceType, + options.itemFactory.createProto(options.itemFactory.stringType), + options.itemFactory.createString("toString")), + true), + new CfLoad(ValueType.INT, 3), + new CfInvoke( + 184, + options.itemFactory.createMethod( + options.itemFactory.createType("Ljava/lang/Long;"), + options.itemFactory.createProto( + options.itemFactory.longType, + options.itemFactory.stringType, + options.itemFactory.intType), + options.itemFactory.createString("parseLong")), + false), + new CfReturn(ValueType.LONG), + label5), + ImmutableList.of(), + ImmutableList.of()); + } + public static CfCode LongMethods_parseUnsignedLong(InternalOptions options, DexMethod method) { CfLabel label0 = new CfLabel(); CfLabel label1 = new CfLabel();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ArgumentRemovalUtils.java b/src/main/java/com/android/tools/r8/ir/optimize/ArgumentRemovalUtils.java index 28bbf14..8f9421d 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/ArgumentRemovalUtils.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/ArgumentRemovalUtils.java
@@ -13,10 +13,10 @@ // Returns true if this method is pinned from the perspective of optimizations that attempt to // remove method arguments. public static boolean isPinned(DexEncodedMethod method, AppView<AppInfoWithLiveness> appView) { - return appView.appInfo().isPinned(method.method) - || appView.appInfo().isBootstrapMethod(method.method) - || appView.appInfo().isFailedResolutionTarget(method.method) - || appView.appInfo().isMethodTargetedByInvokeDynamic(method.method) + return appView.appInfo().isPinned(method.getReference()) + || appView.appInfo().isBootstrapMethod(method.getReference()) + || appView.appInfo().isFailedResolutionTarget(method.getReference()) + || appView.appInfo().isMethodTargetedByInvokeDynamic(method.getReference()) || method.accessFlags.isNative(); } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java b/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java index 5eb23bb..43be45b 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java
@@ -384,12 +384,13 @@ } } } - assert argumentsSeen == code.method().method.getArity() + (code.method().isStatic() ? 0 : 1) + assert argumentsSeen + == code.method().getReference().getArity() + (code.method().isStatic() ? 0 : 1) : "args: " + argumentsSeen + " != " + "arity: " - + code.method().method.getArity() + + code.method().getReference().getArity() + ", static: " + code.method().isStatic(); // After packed Argument instructions, add Assume and constant instructions.
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 b176db1..3551295 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
@@ -164,7 +164,7 @@ // Set initial values for static fields from the definitive static put instructions collected. finalFieldPuts.forEach( (field, put) -> { - DexType fieldType = field.field.type; + DexType fieldType = field.getReference().type; Value value = put.value().getAliasedValue(); if (unnecessaryStaticPuts.contains(put)) { if (fieldType == dexItemFactory.stringType) { @@ -253,7 +253,7 @@ .map(appInfoWithLiveness::resolveField) .map(FieldResolutionResult::getResolvedField) .filter(appInfoWithLiveness::isStaticFieldWrittenOnlyInEnclosingStaticInitializer) - .map(field -> field.field) + .map(field -> field.getReference()) .collect(Collectors.toSet()); // Then retain only these fields that are actually no longer being written to. @@ -264,7 +264,7 @@ DexEncodedField encodedField = appInfoWithLiveness.resolveField(field).getResolvedField(); if (encodedField != null) { - candidates.remove(encodedField.field); + candidates.remove(encodedField.getReference()); } } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java index d3dc297..32ec969 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -263,7 +263,7 @@ if (appView .dexItemFactory() .objectsMethods - .isRequireNonNullMethod(code.method().method)) { + .isRequireNonNullMethod(code.method().getReference())) { continue; } @@ -524,7 +524,8 @@ int selfRecursionFanOut = 0; Instruction lastSelfRecursiveCall = null; for (Instruction i : code.instructions()) { - if (i.isInvokeMethod() && i.asInvokeMethod().getInvokedMethod() == code.method().method) { + if (i.isInvokeMethod() + && i.asInvokeMethod().getInvokedMethod() == code.method().getReference()) { selfRecursionFanOut++; lastSelfRecursiveCall = i; } @@ -3720,7 +3721,7 @@ InstructionListIterator iterator = block.listIterator(code); // Attach some synthetic position to all inserted code. - Position position = Position.synthetic(1, method.method, null); + Position position = Position.synthetic(1, method.getReference(), null); iterator.setInsertionPosition(position); // Split arguments into their own block. @@ -3748,7 +3749,7 @@ Value value = addConstString(code, iterator, "INVOKE "); iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, value))); - value = addConstString(code, iterator, method.method.qualifiedName()); + value = addConstString(code, iterator, method.getReference().qualifiedName()); iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, value))); Value openParenthesis = addConstString(code, iterator, "(");
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java index fa3886e..0cc7497 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
@@ -387,7 +387,7 @@ } // Change the invoke-virtual instruction to target the refined resolution result instead. - return newResolutionResult.getResolvedMethod().method; + return newResolutionResult.getResolvedMethod().getReference(); } private boolean isRebindingNewClassIntoMainDex(ProgramMethod context, DexMethod reboundMethod) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DynamicTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/DynamicTypeOptimization.java index 20e0515..9b738b6 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/DynamicTypeOptimization.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/DynamicTypeOptimization.java
@@ -30,7 +30,7 @@ * <p>If the method has no normal exits, then null is returned. */ public TypeElement computeDynamicReturnType(DexEncodedMethod method, IRCode code) { - assert method.method.proto.returnType.isReferenceType(); + assert method.getReference().proto.returnType.isReferenceType(); List<TypeElement> returnedTypes = new ArrayList<>(); for (BasicBlock block : code.blocks) { JumpInstruction exitInstruction = block.exit(); @@ -43,7 +43,7 @@ } public ClassTypeElement computeDynamicLowerBoundType(DexEncodedMethod method, IRCode code) { - assert method.method.proto.returnType.isReferenceType(); + assert method.getReference().proto.returnType.isReferenceType(); ClassTypeElement result = null; for (BasicBlock block : code.blocks) { JumpInstruction exitInstruction = block.exit();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java index 976e869..e00c267 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -370,6 +370,17 @@ // This will fail at runtime. return ConstraintWithTarget.NEVER; } + if (!appView + .appInfo() + .getClassToFeatureSplitMap() + .isInBaseOrSameFeatureAs( + resolvedMember.getHolderType(), + context.asProgramMethod(), + appView.getSyntheticItems())) { + // We never inline into the base from a feature (calls should never happen) and we + // never inline between features, so this check should be sufficient. + return ConstraintWithTarget.NEVER; + } DexType resolvedHolder = graphLens.lookupType(resolvedMember.getHolderType()); assert initialResolutionHolder != null; ConstraintWithTarget memberConstraintWithTarget =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberPoolCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberPoolCollection.java index 4f699e6..bd0376b 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/MemberPoolCollection.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberPoolCollection.java
@@ -12,6 +12,7 @@ import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.utils.ThreadUtils; import com.android.tools.r8.utils.Timing; +import com.android.tools.r8.utils.WorkList; import com.google.common.base.Equivalence; import com.google.common.base.Equivalence.Wrapper; import java.util.ArrayDeque; @@ -26,6 +27,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; +import java.util.function.BiFunction; import java.util.function.Predicate; // Per-class collection of member signatures. @@ -158,14 +160,16 @@ public static class MemberPool<T> { - private Equivalence<T> equivalence; + private final DexClass clazz; + private final Equivalence<T> equivalence; private MemberPool<T> superType; private final Set<MemberPool<T>> interfaces = new HashSet<>(); private final Set<MemberPool<T>> subTypes = new HashSet<>(); private final Set<Wrapper<T>> memberPool = new HashSet<>(); - MemberPool(Equivalence<T> equivalence) { + MemberPool(Equivalence<T> equivalence, DexClass clazz) { this.equivalence = equivalence; + this.clazz = clazz; } synchronized void linkSupertype(MemberPool<T> superType) { @@ -193,36 +197,74 @@ } public boolean hasSeen(Wrapper<T> member) { - return hasSeenAbove(member, true) || hasSeenStrictlyBelow(member); + return fold(member, false, true, (t, ignored) -> true); } public boolean hasSeenDirectly(Wrapper<T> member) { - return memberPool.contains(member); + return here(member, false, (t, ignored) -> true); } public boolean hasSeenStrictlyAbove(Wrapper<T> member) { - return hasSeenAbove(member, false); - } - - private boolean hasSeenAbove(Wrapper<T> member, boolean inclusive) { - if (inclusive && hasSeenDirectly(member)) { - return true; - } - return (superType != null && superType.hasSeenAbove(member, true)) - || interfaces.stream().anyMatch(itf -> itf.hasSeenAbove(member, true)); + return above(member, false, false, true, (t, ignored) -> true); } public boolean hasSeenStrictlyBelow(Wrapper<T> member) { - return hasSeenBelow(member, false); + return below(member, false, true, (t, ignored) -> true); } - private boolean hasSeenBelow(Wrapper<T> member, boolean inclusive) { - if (inclusive - && (hasSeenDirectly(member) - || interfaces.stream().anyMatch(itf -> itf.hasSeenAbove(member, true)))) { - return true; + private <S> S above( + Wrapper<T> member, + boolean inclusive, + S value, + S terminator, + BiFunction<DexClass, S, S> accumulator) { + WorkList<MemberPool<T>> workList = WorkList.newIdentityWorkList(this); + while (workList.hasNext()) { + MemberPool<T> next = workList.next(); + if (inclusive) { + value = next.here(member, value, accumulator); + if (value == terminator) { + return value; + } + } + inclusive = true; + if (next.superType != null) { + workList.addIfNotSeen(next.superType); + } + workList.addIfNotSeen(next.interfaces); } - return subTypes.stream().anyMatch(subType -> subType.hasSeenBelow(member, true)); + return value; + } + + private <S> S here(Wrapper<T> member, S value, BiFunction<DexClass, S, S> accumulator) { + if (memberPool.contains(member)) { + return accumulator.apply(clazz, value); + } + return value; + } + + public <S> S below( + Wrapper<T> member, S value, S terminator, BiFunction<DexClass, S, S> accumulator) { + WorkList<MemberPool<T>> workList = WorkList.newIdentityWorkList(this.subTypes); + while (workList.hasNext()) { + MemberPool<T> next = workList.next(); + value = next.here(member, value, accumulator); + if (value == terminator) { + return value; + } + workList.addIfNotSeen(next.interfaces); + workList.addIfNotSeen(next.subTypes); + } + return value; + } + + public <S> S fold( + Wrapper<T> member, S initialValue, S terminator, BiFunction<DexClass, S, S> accumulator) { + S value = above(member, true, initialValue, terminator, accumulator); + if (value == terminator) { + return value; + } + return below(member, initialValue, terminator, accumulator); } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java index 593e827..652c185 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
@@ -54,18 +54,19 @@ Runnable computeMemberPoolForClass(DexClass clazz) { return () -> { MemberPool<DexMethod> methodPool = - memberPools.computeIfAbsent(clazz, k -> new MemberPool<>(equivalence)); + memberPools.computeIfAbsent(clazz, k -> new MemberPool<>(equivalence, k)); clazz.forEachMethod( encodedMethod -> { if (methodTester.test(encodedMethod)) { - methodPool.seen(equivalence.wrap(encodedMethod.method)); + methodPool.seen(equivalence.wrap(encodedMethod.getReference())); } }); if (clazz.superType != null) { DexClass superClazz = appView.definitionFor(clazz.superType); if (superClazz != null) { MemberPool<DexMethod> superPool = - memberPools.computeIfAbsent(superClazz, k -> new MemberPool<>(equivalence)); + memberPools.computeIfAbsent( + superClazz, k -> new MemberPool<>(equivalence, superClazz)); superPool.linkSubtype(methodPool); methodPool.linkSupertype(superPool); } @@ -75,7 +76,7 @@ DexClass subClazz = appView.definitionFor(subtype); if (subClazz != null) { MemberPool<DexMethod> childPool = - memberPools.computeIfAbsent(subClazz, k -> new MemberPool<>(equivalence)); + memberPools.computeIfAbsent(subClazz, k -> new MemberPool<>(equivalence, subClazz)); methodPool.linkSubtype(childPool); childPool.linkInterface(methodPool); }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java index f802efe..014337c 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
@@ -363,14 +363,14 @@ fieldInitializationInfos.forEachWithDeterministicOrder( appView, (field, info) -> { - if (!appView.appInfo().withLiveness().mayPropagateValueFor(field.field)) { + if (!appView.appInfo().withLiveness().mayPropagateValueFor(field.getReference())) { return; } if (info.isArgumentInitializationInfo()) { Value value = invoke.getArgument(info.asArgumentInitializationInfo().getArgumentIndex()); Value object = invoke.getReceiver().getAliasedValue(); - FieldAndObject fieldAndObject = new FieldAndObject(field.field, object); + FieldAndObject fieldAndObject = new FieldAndObject(field.getReference(), object); if (field.isFinal()) { activeState.putFinalInstanceField(fieldAndObject, new ExistingValue(value)); } else { @@ -380,7 +380,7 @@ SingleValue value = info.asSingleValue(); if (value.isMaterializableInContext(appView.withLiveness(), method)) { Value object = invoke.getReceiver().getAliasedValue(); - FieldAndObject fieldAndObject = new FieldAndObject(field.field, object); + FieldAndObject fieldAndObject = new FieldAndObject(field.getReference(), object); if (field.isFinal()) { activeState.putFinalInstanceField(fieldAndObject, new MaterializableValue(value)); } else {
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 6758593..d532b9b 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
@@ -178,7 +178,7 @@ }); new Rewriter(code, instructionIterator, serviceLoaderLoad) - .perform(classLoaderInvoke, synthesizedMethod.method); + .perform(classLoaderInvoke, synthesizedMethod.getReference()); } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java index 7bec65e..5536f0e 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
@@ -100,7 +100,7 @@ } private void extractSwitchMap(DexEncodedField encodedField, IRCode initializer) { - DexField field = encodedField.field; + DexField field = encodedField.getReference(); Int2ReferenceMap<DexField> switchMap = new Int2ReferenceArrayMap<>(); // Find each array-put instruction that updates an entry of the array that is stored in @@ -162,7 +162,7 @@ private boolean maybeIsSwitchMap(DexEncodedField dexEncodedField) { // We are looking for synthetic fields of type int[]. - DexField field = dexEncodedField.field; + DexField field = dexEncodedField.getReference(); return dexEncodedField.accessFlags.isSynthetic() && (field.name.startsWith(switchMapPrefix) || field.name.startsWith(kotlinSwitchMapPrefix)) && field.type == intArrayType;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java index d60ba25..df30aac 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
@@ -14,7 +14,7 @@ import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexType; -import com.android.tools.r8.graph.GraphLens.NestedGraphLens; +import com.android.tools.r8.graph.NestedGraphLens; import com.android.tools.r8.graph.RewrittenPrototypeDescription; import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection; import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo; @@ -28,11 +28,9 @@ import com.android.tools.r8.utils.Timing; import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap; import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap; -import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap; import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap; import com.google.common.base.Equivalence.Wrapper; import com.google.common.collect.BiMap; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import java.util.HashMap; @@ -51,21 +49,13 @@ public static class UninstantiatedTypeOptimizationGraphLens extends NestedGraphLens { - private final AppView<?> appView; private final Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod; UninstantiatedTypeOptimizationGraphLens( BidirectionalOneToOneMap<DexMethod, DexMethod> methodMap, Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod, AppView<?> appView) { - super( - ImmutableMap.of(), - methodMap.getForwardMap(), - new EmptyBidirectionalOneToOneMap<>(), - methodMap.getInverseOneToOneMap(), - appView.graphLens(), - appView.dexItemFactory()); - this.appView = appView; + super(appView, EMPTY_FIELD_MAP, methodMap, EMPTY_TYPE_MAP); this.removedArgumentsInfoPerMethod = removedArgumentsInfoPerMethod; } @@ -78,7 +68,8 @@ return prototypeChanges; } if (method.getReturnType().isVoidType() && !previous.getReturnType().isVoidType()) { - prototypeChanges = prototypeChanges.withConstantReturn(previous.getReturnType(), appView); + prototypeChanges = + prototypeChanges.withConstantReturn(previous.getReturnType(), dexItemFactory()); } return prototypeChanges.withRemovedArguments( removedArgumentsInfoPerMethod.getOrDefault(method, ArgumentInfoCollection.empty())); @@ -158,7 +149,7 @@ for (DexEncodedMethod virtualMethod : clazz.virtualMethods()) { RewrittenPrototypeDescription prototypeChanges = RewrittenPrototypeDescription.createForUninstantiatedTypes( - virtualMethod.method, + virtualMethod.getReference(), appView, getRemovedArgumentsInfo(virtualMethod, ALLOW_ARGUMENT_REMOVAL)); if (!prototypeChanges.isEmpty()) { @@ -186,7 +177,7 @@ Set<Wrapper<DexMethod>> usedSignatures = new HashSet<>(); for (DexEncodedMethod method : clazz.methods()) { if (!prototypeChangesPerMethod.containsKey(method)) { - usedSignatures.add(equivalence.wrap(method.method)); + usedSignatures.add(equivalence.wrap(method.getReference())); } } @@ -195,7 +186,7 @@ .getMethodCollection() .replaceDirectMethods( encodedMethod -> { - DexMethod method = encodedMethod.method; + DexMethod method = encodedMethod.getReference(); RewrittenPrototypeDescription prototypeChanges = prototypeChangesPerMethod.getOrDefault( encodedMethod, RewrittenPrototypeDescription.none()); @@ -230,7 +221,7 @@ .getMethodCollection() .replaceVirtualMethods( encodedMethod -> { - DexMethod method = encodedMethod.method; + DexMethod method = encodedMethod.getReference(); RewrittenPrototypeDescription prototypeChanges = getPrototypeChanges(encodedMethod, DISALLOW_ARGUMENT_REMOVAL); ArgumentInfoCollection removedArgumentsInfo = @@ -262,7 +253,7 @@ .getMethodCollection() .replaceVirtualMethods( encodedMethod -> { - DexMethod method = encodedMethod.method; + DexMethod method = encodedMethod.getReference(); RewrittenPrototypeDescription prototypeChanges = getPrototypeChanges(encodedMethod, DISALLOW_ARGUMENT_REMOVAL); ArgumentInfoCollection removedArgumentsInfo = @@ -299,11 +290,11 @@ private RewrittenPrototypeDescription getPrototypeChanges( DexEncodedMethod encodedMethod, Strategy strategy) { if (ArgumentRemovalUtils.isPinned(encodedMethod, appView) - || appView.appInfo().isKeepConstantArgumentsMethod(encodedMethod.method)) { + || appView.appInfo().isKeepConstantArgumentsMethod(encodedMethod.getReference())) { return RewrittenPrototypeDescription.none(); } return RewrittenPrototypeDescription.createForUninstantiatedTypes( - encodedMethod.method, appView, getRemovedArgumentsInfo(encodedMethod, strategy)); + encodedMethod.getReference(), appView, getRemovedArgumentsInfo(encodedMethod, strategy)); } private ArgumentInfoCollection getRemovedArgumentsInfo( @@ -313,7 +304,7 @@ } ArgumentInfoCollection.Builder argInfosBuilder = ArgumentInfoCollection.builder(); - DexProto proto = encodedMethod.method.proto; + DexProto proto = encodedMethod.getReference().proto; int offset = encodedMethod.isStatic() ? 0 : 1; for (int i = 0; i < proto.parameters.size(); ++i) { DexType type = proto.parameters.values[i]; @@ -329,7 +320,7 @@ private DexMethod getNewMethodSignature( DexEncodedMethod encodedMethod, RewrittenPrototypeDescription prototypeChanges) { DexItemFactory dexItemFactory = appView.dexItemFactory(); - DexMethod method = encodedMethod.method; + DexMethod method = encodedMethod.getReference(); DexProto newProto = prototypeChanges.rewriteProto(encodedMethod, dexItemFactory); return dexItemFactory.createMethod(method.holder, newProto, method.name);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java index ec1b904..cc8f5b1 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
@@ -7,14 +7,12 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.ArgumentUse; import com.android.tools.r8.graph.DexEncodedMethod; -import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; -import com.android.tools.r8.graph.GraphLens; -import com.android.tools.r8.graph.GraphLens.NestedGraphLens; +import com.android.tools.r8.graph.NestedGraphLens; import com.android.tools.r8.graph.RewrittenPrototypeDescription; import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection; import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo; @@ -27,10 +25,8 @@ import com.android.tools.r8.utils.Timing; import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap; import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap; -import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap; import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap; import com.google.common.base.Equivalence.Wrapper; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.Streams; import java.util.BitSet; import java.util.HashSet; @@ -57,18 +53,10 @@ private final Map<DexMethod, ArgumentInfoCollection> removedArguments; UnusedArgumentsGraphLens( - Map<DexMethod, DexMethod> methodMap, - BidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures, - GraphLens previousLens, - DexItemFactory dexItemFactory, + AppView<?> appView, + BidirectionalOneToOneMap<DexMethod, DexMethod> methodMap, Map<DexMethod, ArgumentInfoCollection> removedArguments) { - super( - ImmutableMap.of(), - methodMap, - new EmptyBidirectionalOneToOneMap<>(), - originalMethodSignatures, - previousLens, - dexItemFactory); + super(appView, EMPTY_FIELD_MAP, methodMap, EMPTY_TYPE_MAP); this.removedArguments = removedArguments; } @@ -103,12 +91,7 @@ appView.appInfo().classesWithDeterministicOrder().forEach(this::processVirtualMethods); if (!methodMapping.isEmpty()) { - return new UnusedArgumentsGraphLens( - methodMapping.getForwardMap(), - methodMapping.getInverseOneToOneMap(), - appView.graphLens(), - appView.dexItemFactory(), - removedArguments); + return new UnusedArgumentsGraphLens(appView, methodMapping, removedArguments); } return null; @@ -133,8 +116,8 @@ DexString newName = null; do { if (newName == null) { - newName = method.method.name; - } else if (!appView.dexItemFactory().isConstructor(method.method)) { + newName = method.getReference().name; + } else if (!appView.dexItemFactory().isConstructor(method.getReference())) { newName = appView .dexItemFactory() @@ -142,7 +125,7 @@ SymbolGenerationUtils.numberToIdentifier( count, MixedCasing.USE_MIXED_CASE, - method.method.name.toSourceString().toCharArray())); + method.getReference().name.toSourceString().toCharArray())); } else { // Constructors must be named `<init>`. return null; @@ -156,7 +139,7 @@ DexEncodedMethod removeArguments( DexEncodedMethod method, DexMethod newSignature, ArgumentInfoCollection unused) { - boolean removed = usedSignatures.remove(equivalence.wrap(method.method)); + boolean removed = usedSignatures.remove(equivalence.wrap(method.getReference())); assert removed; markSignatureAsUsed(newSignature); @@ -180,10 +163,12 @@ DexString newName = null; do { if (newName == null) { - newName = method.method.name; - } else if (!appView.dexItemFactory().isConstructor(method.method)) { + newName = method.getReference().name; + } else if (!appView.dexItemFactory().isConstructor(method.getReference())) { newName = - appView.dexItemFactory().createString(method.method.name.toSourceString() + count); + appView + .dexItemFactory() + .createString(method.getReference().name.toSourceString() + count); } else { // Constructors must be named `<init>`. return null; @@ -210,7 +195,7 @@ private void processDirectMethods(DexProgramClass clazz) { UsedSignatures signatures = new UsedSignatures(); for (DexEncodedMethod method : clazz.methods()) { - signatures.markSignatureAsUsed(method.method); + signatures.markSignatureAsUsed(method.getReference()); } clazz @@ -220,7 +205,7 @@ // If this is a method with known resolution issues, then don't remove any unused // arguments. - if (appView.appInfo().isFailedResolutionTarget(method.method)) { + if (appView.appInfo().isFailedResolutionTarget(method.getReference())) { return method; } @@ -229,14 +214,14 @@ DexProto newProto = createProtoWithRemovedArguments(method, unused); DexMethod newSignature = signatures.getNewSignature(method, newProto); if (newSignature == null) { - assert appView.dexItemFactory().isConstructor(method.method); + assert appView.dexItemFactory().isConstructor(method.getReference()); return method; } DexEncodedMethod newMethod = signatures.removeArguments(method, newSignature, unused); synchronized (this) { - methodMapping.put(method.method, newMethod.method); - removedArguments.put(newMethod.method, unused); + methodMapping.put(method.getReference(), newMethod.getReference()); + removedArguments.put(newMethod.getReference(), unused); } return newMethod; } @@ -265,8 +250,8 @@ signatures.removeArguments( method, signatures.getNewSignature(method, newProto), unused); - methodMapping.put(method.method, newMethod.method); - removedArguments.put(newMethod.method, unused); + methodMapping.put(method.getReference(), newMethod.getReference()); + removedArguments.put(newMethod.getReference(), unused); return newMethod; } return method; @@ -280,7 +265,7 @@ private ArgumentInfoCollection collectUnusedArguments( DexEncodedMethod method, MemberPool<DexMethod> methodPool) { if (ArgumentRemovalUtils.isPinned(method, appView) - || appView.appInfo().isKeepUnusedArgumentsMethod(method.method)) { + || appView.appInfo().isKeepUnusedArgumentsMethod(method.getReference())) { return null; } // Only process classfile code objects. @@ -292,13 +277,13 @@ // an unused argument cannot be removed unless it is unused in all of the related methods in // the hierarchy. assert methodPool != null; - Wrapper<DexMethod> wrapper = equivalence.wrap(method.method); + Wrapper<DexMethod> wrapper = equivalence.wrap(method.getReference()); if (methodPool.hasSeenStrictlyAbove(wrapper) || methodPool.hasSeenStrictlyBelow(wrapper)) { return null; } } int offset = method.accessFlags.isStatic() ? 0 : 1; - int argumentCount = method.method.proto.parameters.size() + offset; + int argumentCount = method.getReference().proto.parameters.size() + offset; CollectUsedArguments collector = new CollectUsedArguments(); if (!method.accessFlags.isStatic()) { // TODO(65810338): The receiver cannot be removed without transforming the method to being @@ -313,7 +298,7 @@ if (!used.get(argumentIndex)) { RemovedArgumentInfo removedArg = RemovedArgumentInfo.builder() - .setType(method.method.proto.parameters.values[argumentIndex - offset]) + .setType(method.getReference().proto.parameters.values[argumentIndex - offset]) .build(); argInfosBuilder.addArgumentInfo(argumentIndex, removedArg); } @@ -326,7 +311,9 @@ private DexProto createProtoWithRemovedArguments( DexEncodedMethod encodedMethod, ArgumentInfoCollection unused) { DexType[] parameters = unused.rewriteParameters(encodedMethod); - return appView.dexItemFactory().createProto(encodedMethod.method.proto.returnType, parameters); + return appView + .dexItemFactory() + .createProto(encodedMethod.getReference().proto.returnType, parameters); } private static class CollectUsedArguments extends ArgumentUse {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java index 4857999..f7b79aa 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -290,8 +290,8 @@ // Class must not define finalizer. DexItemFactory dexItemFactory = appView.dexItemFactory(); for (DexEncodedMethod method : clazz.virtualMethods()) { - if (method.method.name == dexItemFactory.finalizeMethodName - && method.method.proto == dexItemFactory.objectMembers.finalize.proto) { + if (method.getReference().name == dexItemFactory.finalizeMethodName + && method.getReference().proto == dexItemFactory.objectMembers.finalize.proto) { return EligibilityStatus.NOT_ELIGIBLE; } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java index 27deb32..ce781ec 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -341,7 +341,7 @@ eligibleEnums.add(type); } } else if (use.isReturn()) { - DexType returnType = code.method().method.proto.returnType; + DexType returnType = code.method().getReference().proto.returnType; if (enumUnboxingCandidatesInfo.isCandidate(returnType)) { eligibleEnums.add(returnType); } @@ -500,7 +500,7 @@ for (DexEncodedField staticField : enumClass.staticFields()) { if (factory.enumMembers.isEnumField(staticField, enumClass.type)) { ObjectState enumState = - enumStaticFieldValues.getObjectStateForPossiblyPinnedField(staticField.field); + enumStaticFieldValues.getObjectStateForPossiblyPinnedField(staticField.getReference()); if (enumState == null) { if (staticField.getOptimizationInfo().isDead()) { // We don't care about unused field data. @@ -514,11 +514,11 @@ return null; } int ordinal = optionalOrdinal.getAsInt(); - unboxedValues.put(staticField.field, ordinalToUnboxedInt(ordinal)); + unboxedValues.put(staticField.getReference(), ordinalToUnboxedInt(ordinal)); ordinalToObjectState.put(ordinal, enumState); } else if (factory.enumMembers.isValuesFieldCandidate(staticField, enumClass.type)) { ObjectState valuesState = - enumStaticFieldValues.getObjectStateForPossiblyPinnedField(staticField.field); + enumStaticFieldValues.getObjectStateForPossiblyPinnedField(staticField.getReference()); if (valuesState == null) { if (staticField.getOptimizationInfo().isDead()) { // We don't care about unused field data. @@ -533,7 +533,7 @@ assert valuesContents == null || valuesContents.equals(valuesState.asEnumValuesObjectState()); valuesContents = valuesState.asEnumValuesObjectState(); - valuesField.add(staticField.field); + valuesField.add(staticField.getReference()); } } @@ -1012,7 +1012,7 @@ return Reason.ELIGIBLE; } // The put value has to be of the field type. - if (field.field.type.toBaseType(factory) != enumClass.type) { + if (field.getReference().type.toBaseType(factory) != enumClass.type) { return Reason.TYPE_MISMATCH_FIELD_PUT; } return Reason.ELIGIBLE; @@ -1095,7 +1095,7 @@ // Return is used for valueOf methods. if (instruction.isReturn()) { - DexType returnType = code.method().method.proto.returnType; + DexType returnType = code.method().getReference().proto.returnType; if (returnType != enumClass.type && returnType.toBaseType(factory) != enumClass.type) { return Reason.IMPLICIT_UP_CAST_IN_RETURN; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java index 88845d9..0d1c0fa 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
@@ -85,18 +85,18 @@ } static boolean isEnumField(DexEncodedField staticField, DexType enumType) { - return staticField.field.type == enumType + return staticField.getReference().type == enumType && staticField.accessFlags.isEnum() && staticField.accessFlags.isFinal(); } static boolean matchesValuesField( DexEncodedField staticField, DexType enumType, DexItemFactory factory) { - return staticField.field.type.isArrayType() - && staticField.field.type.toArrayElementType(factory) == enumType + return staticField.getReference().type.isArrayType() + && staticField.getReference().type.toArrayElementType(factory) == enumType && staticField.accessFlags.isSynthetic() && staticField.accessFlags.isFinal() - && staticField.field.name == factory.enumValuesFieldName; + && staticField.getReference().name == factory.enumValuesFieldName; } private void removeEnumsInAnnotations() {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java index c64e51e..1e27370 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
@@ -4,11 +4,11 @@ package com.android.tools.r8.ir.optimize.enums; +import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexField; -import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexType; -import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.NestedGraphLens; import com.android.tools.r8.graph.RewrittenPrototypeDescription; import com.android.tools.r8.ir.code.Invoke; import com.android.tools.r8.utils.BooleanUtils; @@ -16,34 +16,21 @@ import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap; import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import java.util.IdentityHashMap; import java.util.Map; -import java.util.Set; -class EnumUnboxingLens extends GraphLens.NestedGraphLens { +class EnumUnboxingLens extends NestedGraphLens { private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod; - private final Set<DexType> unboxedEnums; EnumUnboxingLens( - Map<DexType, DexType> typeMap, - Map<DexMethod, DexMethod> methodMap, + AppView<?> appView, BidirectionalOneToOneMap<DexField, DexField> fieldMap, - BidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures, - GraphLens previousLens, - DexItemFactory dexItemFactory, - Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod, - Set<DexType> unboxedEnums) { - super( - typeMap, - methodMap, - fieldMap, - originalMethodSignatures, - previousLens, - dexItemFactory); + BidirectionalOneToOneMap<DexMethod, DexMethod> methodMap, + Map<DexType, DexType> typeMap, + Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod) { + super(appView, fieldMap, methodMap, typeMap); this.prototypeChangesPerMethod = prototypeChangesPerMethod; - this.unboxedEnums = unboxedEnums; } @Override @@ -59,7 +46,7 @@ @Override protected Invoke.Type mapInvocationType( DexMethod newMethod, DexMethod originalMethod, Invoke.Type type) { - if (unboxedEnums.contains(originalMethod.holder)) { + if (typeMap.containsKey(originalMethod.getHolderType())) { // Methods moved from unboxed enums to the utility class are either static or statified. assert newMethod != originalMethod; return Invoke.Type.STATIC; @@ -76,7 +63,7 @@ protected final Map<DexType, DexType> typeMap = new IdentityHashMap<>(); protected final MutableBidirectionalOneToOneMap<DexField, DexField> newFieldSignatures = new BidirectionalOneToOneHashMap<>(); - protected final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures = + protected final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> newMethodSignatures = new BidirectionalOneToOneHashMap<>(); private Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod = @@ -107,7 +94,7 @@ boolean toStatic, int numberOfExtraNullParameters) { assert from != to; - originalMethodSignatures.put(to, from); + newMethodSignatures.put(from, to); int offsetDiff = 0; int toOffset = BooleanUtils.intValue(!toStatic); RewrittenPrototypeDescription.ArgumentInfoCollection.Builder builder = @@ -140,18 +127,14 @@ .withExtraUnusedNullParameters(numberOfExtraNullParameters)); } - public EnumUnboxingLens build( - DexItemFactory dexItemFactory, GraphLens previousLens, Set<DexType> unboxedEnums) { + public EnumUnboxingLens build(AppView<?> appView) { assert !typeMap.isEmpty(); return new EnumUnboxingLens( - typeMap, - originalMethodSignatures.getInverseOneToOneMap().getForwardMap(), + appView, newFieldSignatures, - originalMethodSignatures, - previousLens, - dexItemFactory, - ImmutableMap.copyOf(prototypeChangesPerMethod), - ImmutableSet.copyOf(unboxedEnums)); + newMethodSignatures, + typeMap, + ImmutableMap.copyOf(prototypeChangesPerMethod)); } } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java index 1602032..4fdd8f6 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
@@ -21,7 +21,6 @@ import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature; -import com.android.tools.r8.graph.GraphLens.NestedGraphLens; import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.ParameterAnnotationsList; import com.android.tools.r8.graph.ProgramMethod; @@ -72,7 +71,7 @@ private final DexItemFactory factory; private final EnumDataMap unboxedEnumsData; private final UnboxedEnumMemberRelocator relocator; - private NestedGraphLens enumUnboxingLens; + private EnumUnboxingLens enumUnboxingLens; private final Map<DexMethod, DexEncodedMethod> utilityMethods = new ConcurrentHashMap<>(); @@ -128,7 +127,7 @@ ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "zeroCheckMessage"); } - public void setEnumUnboxingLens(NestedGraphLens enumUnboxingLens) { + public void setEnumUnboxingLens(EnumUnboxingLens enumUnboxingLens) { this.enumUnboxingLens = enumUnboxingLens; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java index 17d0cc7..8a43d7c 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -89,7 +89,7 @@ DexProgramClass newHolderClass = appView.definitionFor(newHolderType).asProgramClass(); newHolderClass.addDirectMethods(movedMethods); }); - return lensBuilder.build(factory, appView.graphLens(), enumsToUnbox); + return lensBuilder.build(appView); } private void clearEnumToUnboxMethod(DexEncodedMethod enumMethod) { @@ -103,7 +103,7 @@ private DexEncodedMethod fixupEncodedMethodToUtility( DexEncodedMethod encodedMethod, DexType newHolder) { - DexMethod method = encodedMethod.method; + DexMethod method = encodedMethod.getReference(); DexString newMethodName = factory.createString( enumUnboxerRewriter.compatibleName(method.holder) @@ -137,9 +137,10 @@ method.getName().toString() + (method.isNonPrivateVirtualMethod() ? "$enumunboxing$" : ""); DexMethod newMethod = factory.createMethod(method.getHolderType(), newProto, newMethodName); newMethod = ensureUniqueMethod(method, newMethod); - int numberOfExtraNullParameters = newMethod.getArity() - method.method.getArity(); + int numberOfExtraNullParameters = newMethod.getArity() - method.getReference().getArity(); boolean isStatic = method.isStatic(); - lensBuilder.move(method.method, newMethod, isStatic, isStatic, numberOfExtraNullParameters); + lensBuilder.move( + method.getReference(), newMethod, isStatic, isStatic, numberOfExtraNullParameters); return method.toTypeSubstitutedMethod( newMethod, builder -> @@ -195,7 +196,7 @@ } for (int i = 0; i < fields.size(); i++) { DexEncodedField encodedField = fields.get(i); - DexField field = encodedField.field; + DexField field = encodedField.getReference(); DexType newType = fixupType(field.type); if (newType != field.type) { DexField newField = factory.createField(field.holder, newType, field.name);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java index 7ad0bdb..70b07a6 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
@@ -144,7 +144,7 @@ .appInfo() .resolveMethodOnClass(factory.objectMembers.toString, enumFieldType.getClassType()) .getSingleTarget(); - if (singleTarget != null && singleTarget.method != factory.enumMembers.toString) { + if (singleTarget != null && singleTarget.getReference() != factory.enumMembers.toString) { continue; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java index ab2b0ac..83fdf6a 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java
@@ -81,13 +81,13 @@ private TypeElement[] getStaticTypes(AppView<?> appView, DexEncodedMethod method) { int argOffset = method.isStatic() ? 0 : 1; - int size = method.method.getArity() + argOffset; + int size = method.getReference().getArity() + argOffset; TypeElement[] staticTypes = new TypeElement[size]; if (!method.isStatic()) { staticTypes[0] = TypeElement.fromDexType(method.getHolderType(), definitelyNotNull(), appView); } - for (int i = 0; i < method.method.getArity(); i++) { + for (int i = 0; i < method.getReference().getArity(); i++) { staticTypes[i + argOffset] = TypeElement.fromDexType(method.getParameter(i), maybeNull(), appView); }
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 aa28923..a48292a 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
@@ -215,7 +215,7 @@ IRCode code, OptimizationFeedback feedback, InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos) { - assert !appView.appInfo().isPinned(method.method); + assert !appView.appInfo().isPinned(method.getReference()); if (!method.isInstanceInitializer()) { return; @@ -227,7 +227,7 @@ return; } - if (appView.appInfo().mayHaveSideEffects.containsKey(method.method)) { + if (appView.appInfo().mayHaveSideEffects.containsKey(method.getReference())) { return; } @@ -813,7 +813,7 @@ DexEncodedMethod method, IRCode code) { if (dynamicTypeOptimization != null) { - DexType staticReturnTypeRaw = method.method.proto.returnType; + DexType staticReturnTypeRaw = method.getReference().proto.returnType; if (!staticReturnTypeRaw.isReferenceType()) { return; } @@ -887,7 +887,7 @@ if (!options.enableSideEffectAnalysis) { return; } - if (appView.appInfo().mayHaveSideEffects.containsKey(method.method)) { + if (appView.appInfo().mayHaveSideEffects.containsKey(method.getReference())) { return; } ProgramMethod context = code.context(); @@ -954,8 +954,8 @@ .resolveMethodOnClass(appView.dexItemFactory().objectMembers.finalize, clazz); DexEncodedMethod target = resolutionResult.getSingleTarget(); return target != null - && target.method != dexItemFactory.enumMembers.finalize - && target.method != dexItemFactory.objectMembers.finalize; + && target.getReference() != dexItemFactory.enumMembers.finalize + && target.getReference() != dexItemFactory.objectMembers.finalize; } private void computeReturnValueOnlyDependsOnArguments(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java index df06045..5a12983 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -108,11 +108,10 @@ public boolean noUpdatesLeft() { assert appInfoWithLivenessModifier.isEmpty(); assert fieldOptimizationInfos.isEmpty() - : StringUtils.join(fieldOptimizationInfos.keySet(), ", "); + : StringUtils.join(", ", fieldOptimizationInfos.keySet()); assert methodOptimizationInfos.isEmpty() - : StringUtils.join(methodOptimizationInfos.keySet(), ", "); - assert processed.isEmpty() - : StringUtils.join(processed.keySet(), ", "); + : StringUtils.join(", ", methodOptimizationInfos.keySet()); + assert processed.isEmpty() : StringUtils.join(", ", processed.keySet()); return true; } @@ -151,9 +150,13 @@ @Override public void recordFieldHasAbstractValue( DexEncodedField field, AppView<AppInfoWithLiveness> appView, AbstractValue abstractValue) { - assert appView.appInfo().getFieldAccessInfoCollection().contains(field.field); - assert !appView.appInfo().getFieldAccessInfoCollection().get(field.field).hasReflectiveAccess(); - if (appView.appInfo().mayPropagateValueFor(field.field)) { + assert appView.appInfo().getFieldAccessInfoCollection().contains(field.getReference()); + assert !appView + .appInfo() + .getFieldAccessInfoCollection() + .get(field.getReference()) + .hasReflectiveAccess(); + if (appView.appInfo().mayPropagateValueFor(field.getReference())) { getFieldOptimizationInfoForUpdating(field).setAbstractValue(abstractValue); } } @@ -190,7 +193,7 @@ @Override public synchronized void methodReturnsAbstractValue( DexEncodedMethod method, AppView<AppInfoWithLiveness> appView, AbstractValue value) { - if (appView.appInfo().mayPropagateValueFor(method.method)) { + if (appView.appInfo().mayPropagateValueFor(method.getReference())) { getMethodOptimizationInfoForUpdating(method).markReturnsAbstractValue(value); } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java index 3fb77d9..5c39d40 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -66,7 +66,7 @@ @Override public void recordFieldHasAbstractValue( DexEncodedField field, AppView<AppInfoWithLiveness> appView, AbstractValue abstractValue) { - if (appView.appInfo().mayPropagateValueFor(field.field)) { + if (appView.appInfo().mayPropagateValueFor(field.getReference())) { field.getMutableOptimizationInfo().setAbstractValue(abstractValue); } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java index 9fa412a..aca1f76 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java
@@ -47,7 +47,7 @@ public void recordInitializationInfo( DexEncodedField field, InstanceFieldInitializationInfo info) { - recordInitializationInfo(field.field, info); + recordInitializationInfo(field.getReference(), info); } public Builder recordInitializationInfo(DexField field, InstanceFieldInitializationInfo info) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java index 6fa0363..2081721 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
@@ -57,7 +57,8 @@ @Override public InstanceFieldInitializationInfo get(DexEncodedField field) { - return infos.getOrDefault(field.field, UnknownInstanceFieldInitializationInfo.getInstance()); + return infos.getOrDefault( + field.getReference(), UnknownInstanceFieldInitializationInfo.getInstance()); } @Override @@ -85,7 +86,7 @@ List<String> strings = new ArrayList<>(); infos.forEach((field, info) -> strings.add(field.toSourceString() + " -> " + info)); return "NonTrivialInstanceFieldInitializationInfoCollection(" - + StringUtils.join(strings, "; ") + + StringUtils.join("; ", strings) + ")"; } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java index ee2d4b5..257cc15 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
@@ -147,7 +147,7 @@ "not a valid inlining reason (was: " + reason + ", allowed: one of " - + StringUtils.join(validInliningReasons, ", ") + + StringUtils.join(", ", validInliningReasons) + ")."); }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryOptimizationInfoInitializer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryOptimizationInfoInitializer.java index 2de1eb0..b986800 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryOptimizationInfoInitializer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryOptimizationInfoInitializer.java
@@ -94,7 +94,8 @@ for (DexEncodedField field : finalLibraryFields) { if (field.isStatic()) { feedback.recordLibraryFieldHasAbstractValue( - field, abstractValueFactory.createSingleFieldValue(field.field, ObjectState.empty())); + field, + abstractValueFactory.createSingleFieldValue(field.getReference(), ObjectState.empty())); } } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java index 5a2f63a..7761bfa 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
@@ -128,7 +128,7 @@ // field. The requirements for the initialization of this field will be // checked later. for (DexEncodedField field : cls.staticFields()) { - DexType type = field.field.type; + DexType type = field.getReference().type; if (singletonFields.put(type, field) != null) { // There is already candidate singleton field found. markNotEligible(type, notEligible); @@ -137,7 +137,7 @@ // Don't allow fields with this candidate types. for (DexEncodedField field : cls.instanceFields()) { - markNotEligible(field.field.type, notEligible); + markNotEligible(field.getReference().type, notEligible); } // Don't allow methods that take a value of this type. @@ -192,11 +192,11 @@ private boolean isPinned(DexClass clazz, DexEncodedField singletonField) { AppInfoWithLiveness appInfo = appView.appInfo(); - if (appInfo.isPinned(clazz.type) || appInfo.isPinned(singletonField.field)) { + if (appInfo.isPinned(clazz.type) || appInfo.isPinned(singletonField.getReference())) { return true; } for (DexEncodedMethod method : clazz.methods()) { - if (!method.isStatic() && appInfo.isPinned(method.method)) { + if (!method.isStatic() && appInfo.isPinned(method.getReference())) { return true; } } @@ -589,7 +589,7 @@ if (invoke.hasOutValue() && candidateInfo.getter.get() != null - && candidateInfo.getter.get().method == invoke.getInvokedMethod()) { + && candidateInfo.getter.get().getReference() == invoke.getInvokedMethod()) { candidateInfo = analyzeAllValueUsers(candidateInfo, invoke.outValue(), false); } return candidateInfo;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLens.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLens.java index 75a78ab..c5f6ddc 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLens.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLens.java
@@ -7,10 +7,9 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexMethod; -import com.android.tools.r8.graph.GraphLens.NestedGraphLens; +import com.android.tools.r8.graph.NestedGraphLens; import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap; -import com.google.common.collect.ImmutableMap; class ClassStaticizerGraphLens extends NestedGraphLens { @@ -18,13 +17,7 @@ AppView<?> appView, BidirectionalOneToOneMap<DexField, DexField> fieldMapping, BidirectionalOneToOneMap<DexMethod, DexMethod> methodMapping) { - super( - ImmutableMap.of(), - methodMapping.getForwardMap(), - fieldMapping, - methodMapping.getInverseOneToOneMap(), - appView.graphLens(), - appView.dexItemFactory()); + super(appView, fieldMapping, methodMapping, EMPTY_TYPE_MAP); } @Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java index 27806d5..69d65c8 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -253,13 +253,15 @@ .filter( instruction -> { if (instruction.isStaticGet() - && instruction.asStaticGet().getField() == info.singletonField.field) { + && instruction.asStaticGet().getField() + == info.singletonField.getReference()) { return true; } DexEncodedMethod getter = info.getter.get(); return getter != null && instruction.isInvokeStatic() - && instruction.asInvokeStatic().getInvokedMethod() == getter.method; + && instruction.asInvokeStatic().getInvokedMethod() + == getter.getReference(); }) .collect(Collectors.toList()); boolean fixableFieldReadsPerUsage = true; @@ -319,10 +321,10 @@ return false; }, methodsToBeStaticized::add); - singletonFields.put(candidate.singletonField.field, candidate); + singletonFields.put(candidate.singletonField.getReference(), candidate); DexEncodedMethod getter = candidate.getter.get(); if (getter != null) { - singletonGetters.put(getter.method, candidate); + singletonGetters.put(getter.getReference(), candidate); } ProgramMethodSet referencedFrom = materializedReferencedFromCollections.getOrDefault(candidate, ProgramMethodSet.empty()); @@ -447,7 +449,8 @@ if (newInstance.outValue().hasAnyUsers()) { TypeElement type = TypeElement.fromDexType(newInstance.clazz, maybeNull(), appView); newInstance.replace( - new StaticGet(code.createValue(type), candidateInfo.singletonField.field), code); + new StaticGet(code.createValue(type), candidateInfo.singletonField.getReference()), + code); } else { newInstance.removeOrReplaceByDebugLocalRead(code); } @@ -753,11 +756,11 @@ for (DexEncodedMethod method : candidateClass.methods()) { if (method.isStatic()) { newDirectMethods.add(method); - } else if (!factory().isConstructor(method.method)) { + } else if (!factory().isConstructor(method.getReference())) { DexEncodedMethod staticizedMethod = method.toStaticMethodWithoutThis(); newDirectMethods.add(staticizedMethod); staticizedMethods.createAndAdd(candidateClass, staticizedMethod); - methodMapping.put(method.method, staticizedMethod.method); + methodMapping.put(method.getReference(), staticizedMethod.getReference()); } } candidateClass.setVirtualMethods(DexEncodedMethod.EMPTY_ARRAY); @@ -786,8 +789,9 @@ private boolean classMembersConflict(DexClass a, DexClass b) { assert Streams.stream(a.methods()).allMatch(DexEncodedMethod::isStatic); assert a.instanceFields().size() == 0; - return a.staticFields().stream().anyMatch(fld -> b.lookupField(fld.field) != null) - || Streams.stream(a.methods()).anyMatch(method -> b.lookupMethod(method.method) != null); + return a.staticFields().stream().anyMatch(fld -> b.lookupField(fld.getReference()) != null) + || Streams.stream(a.methods()) + .anyMatch(method -> b.lookupMethod(method.getReference()) != null); } private boolean hasMembersNotStaticized( @@ -818,10 +822,10 @@ List<DexEncodedField> oldFields = hostClass.staticFields(); for (int i = 0; i < oldFields.size(); i++) { DexEncodedField field = oldFields.get(i); - DexField newField = mapCandidateField(field.field, candidateClass.type, hostType); - if (newField != field.field) { + DexField newField = mapCandidateField(field.getReference(), candidateClass.type, hostType); + if (newField != field.getReference()) { newFields[i] = field.toTypeSubstitutedField(newField); - fieldMapping.put(field.field, newField); + fieldMapping.put(field.getReference(), newField); } else { newFields[i] = field; } @@ -830,10 +834,10 @@ List<DexEncodedField> extraFields = candidateClass.staticFields(); for (int i = 0; i < extraFields.size(); i++) { DexEncodedField field = extraFields.get(i); - DexField newField = mapCandidateField(field.field, candidateClass.type, hostType); - if (newField != field.field) { + DexField newField = mapCandidateField(field.getReference(), candidateClass.type, hostType); + if (newField != field.getReference()) { newFields[numOfHostStaticFields + i] = field.toTypeSubstitutedField(newField); - fieldMapping.put(field.field, newField); + fieldMapping.put(field.getReference(), newField); } else { newFields[numOfHostStaticFields + i] = field; } @@ -852,7 +856,8 @@ for (DexEncodedMethod method : extraMethods) { DexEncodedMethod newMethod = method.toTypeSubstitutedMethod( - factory().createMethod(hostType, method.method.proto, method.method.name)); + factory() + .createMethod(hostType, method.getReference().proto, method.getReference().name)); newMethods.add(newMethod); // If the old method from the candidate class has been staticized, if (staticizedMethods.remove(method)) { @@ -860,11 +865,11 @@ // has just been migrated to the host class. staticizedMethods.createAndAdd(hostClass, newMethod); } - DexMethod originalMethod = methodMapping.getRepresentativeKey(method.method); + DexMethod originalMethod = methodMapping.getRepresentativeKey(method.getReference()); if (originalMethod == null) { - methodMapping.put(method.method, newMethod.method); + methodMapping.put(method.getReference(), newMethod.getReference()); } else { - methodMapping.put(originalMethod, newMethod.method); + methodMapping.put(originalMethod, newMethod.getReference()); } } hostClass.addDirectMethods(newMethods);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java index 5fdaf51..ca49a7d 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java
@@ -540,7 +540,7 @@ if (contents == null || contents.isEmpty()) { return; } - String result = StringUtils.join(contents, ""); + String result = StringUtils.join("", contents); Integer size = Integer.valueOf(contents.size()); Integer length = Integer.valueOf(result.length()); if (isPartial) { @@ -712,7 +712,7 @@ builder, optimizationConfiguration)) { return null; } - String result = StringUtils.join(contents, ""); + String result = StringUtils.join("", contents); int estimate = estimateSizeReduction(contents); return estimate > result.length() ? result : null; }
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java index 012bd0e..179dffd 100644 --- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java +++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -609,7 +609,7 @@ if (intervals == null) { throw new CompilationError( "Unexpected attempt to get register for a value without a register in method `" - + code.method().method.toSourceString() + + code.method().getReference().toSourceString() + "`.", code.origin); }
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/RecordGetFieldsAsObjectsCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/RecordGetFieldsAsObjectsCfCodeProvider.java new file mode 100644 index 0000000..4f534da --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/synthetic/RecordGetFieldsAsObjectsCfCodeProvider.java
@@ -0,0 +1,102 @@ +// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.ir.synthetic; + +import com.android.tools.r8.cf.code.CfArrayStore; +import com.android.tools.r8.cf.code.CfConstNumber; +import com.android.tools.r8.cf.code.CfFieldInstruction; +import com.android.tools.r8.cf.code.CfInstruction; +import com.android.tools.r8.cf.code.CfInvoke; +import com.android.tools.r8.cf.code.CfLoad; +import com.android.tools.r8.cf.code.CfNewArray; +import com.android.tools.r8.cf.code.CfReturn; +import com.android.tools.r8.cf.code.CfStore; +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.CfCode; +import com.android.tools.r8.graph.DexField; +import com.android.tools.r8.graph.DexItemFactory; +import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.ir.code.MemberType; +import com.android.tools.r8.ir.code.ValueType; +import java.util.ArrayList; +import java.util.List; +import org.objectweb.asm.Opcodes; + +/** + * Generates a method which answers all field values as an array of objects. If the field value is a + * primitive type, it uses the primitive wrapper to wrap it. + * + * <p>The fields in parameters are in the order where they should be in the array generated by the + * method, which is not necessarily the class instanceFields order. + * + * <p>Example: <code>record Person{ int age; String name;}</code> + * + * <p><code>Object[] getFieldsAsObjects() { + * Object[] fields = new Object[2]; + * fields[0] = name; + * fields[1] = Integer.valueOf(age); + * return fields;</code> + */ +public class RecordGetFieldsAsObjectsCfCodeProvider extends SyntheticCfCodeProvider { + + public static void registerSynthesizedCodeReferences(DexItemFactory factory) { + factory.createSynthesizedType("[Ljava/lang/Object;"); + factory.primitiveToBoxed.forEach( + (primitiveType, boxedType) -> { + factory.createSynthesizedType(primitiveType.toDescriptorString()); + factory.createSynthesizedType(boxedType.toDescriptorString()); + }); + } + + private final DexField[] fields; + + public RecordGetFieldsAsObjectsCfCodeProvider( + AppView<?> appView, DexType holder, DexField[] fields) { + super(appView, holder); + this.fields = fields; + } + + @Override + public CfCode generateCfCode() { + // Stack layout: + // 0 : receiver (the record instance) + // 1 : the array to return + // 2+: spills + DexItemFactory factory = appView.dexItemFactory(); + List<CfInstruction> instructions = new ArrayList<>(); + // Object[] fields = new Object[*length*]; + instructions.add(new CfConstNumber(fields.length, ValueType.INT)); + instructions.add(new CfNewArray(factory.objectArrayType)); + instructions.add(new CfStore(ValueType.OBJECT, 1)); + // fields[*i*] = this.*field* || *PrimitiveWrapper*.valueOf(this.*field*); + for (int i = 0; i < fields.length; i++) { + DexField field = fields[i]; + instructions.add(new CfLoad(ValueType.OBJECT, 1)); + instructions.add(new CfConstNumber(i, ValueType.INT)); + instructions.add(new CfLoad(ValueType.OBJECT, 0)); + instructions.add(new CfFieldInstruction(Opcodes.GETFIELD, field, field)); + if (field.type.isPrimitiveType()) { + factory.primitiveToBoxed.forEach( + (primitiveType, boxedType) -> { + if (primitiveType == field.type) { + instructions.add( + new CfInvoke( + Opcodes.INVOKESTATIC, + factory.createMethod( + boxedType, + factory.createProto(boxedType, primitiveType), + factory.valueOfMethodName), + false)); + } + }); + } + instructions.add(new CfArrayStore(MemberType.OBJECT)); + } + // return fields; + instructions.add(new CfLoad(ValueType.OBJECT, 1)); + instructions.add(new CfReturn(ValueType.OBJECT)); + return standardCfCodeFromInstructions(instructions); + } +}
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 1587e8a..5ade4de 100644 --- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java +++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -218,9 +218,9 @@ if (clazz.isRecord()) { // TODO(b/169645628): Strip record components if not kept. for (DexEncodedField instanceField : clazz.instanceFields()) { - String componentName = namingLens.lookupName(instanceField.field).toString(); + String componentName = namingLens.lookupName(instanceField.getReference()).toString(); String componentDescriptor = - namingLens.lookupDescriptor(instanceField.field.type).toString(); + namingLens.lookupDescriptor(instanceField.getReference().type).toString(); String componentSignature = instanceField.getGenericSignature().toRenamedString(namingLens, isTypeMissing); writer.visitRecordComponent(componentName, componentDescriptor, componentSignature); @@ -239,7 +239,9 @@ } if (options.desugarSpecificOptions().sortMethodsOnCfOutput) { SortedSet<ProgramMethod> programMethodSortedSet = - Sets.newTreeSet((a, b) -> a.getDefinition().method.compareTo(b.getDefinition().method)); + Sets.newTreeSet( + (a, b) -> + a.getDefinition().getReference().compareTo(b.getDefinition().getReference())); clazz.forEachProgramMethod(programMethodSortedSet::add); programMethodSortedSet.forEach( method -> writeMethod(method, version, rewriter, writer, defaults)); @@ -268,7 +270,7 @@ // In this case bridges have been introduced for the Cf back-end, // which do not have class file version. assert options.isDesugaredLibraryCompilation() || options.cfToCfDesugar - : "Expected class file version for " + method.method.toSourceString(); + : "Expected class file version for " + method.getReference().toSourceString(); assert MIN_VERSION_FOR_COMPILER_GENERATED_CODE.isLessThan( options.classFileVersionAfterDesugaring(InternalOptions.SUPPORTED_CF_VERSION)); // Any desugaring rewrites which cannot meet the default class file version after @@ -355,8 +357,8 @@ if (field.isDeprecated()) { access = AsmUtils.withDeprecated(access); } - String name = namingLens.lookupName(field.field).toString(); - String desc = namingLens.lookupDescriptor(field.field.type).toString(); + String name = namingLens.lookupName(field.getReference()).toString(); + String desc = namingLens.lookupDescriptor(field.getReference().type).toString(); String signature = field.getGenericSignature().toRenamedString(namingLens, isTypeMissing); Object value = getStaticValue(field); FieldVisitor visitor = writer.visitField(access, name, desc, signature, value);
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java index d9baf1f..f10902f 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
@@ -93,11 +93,11 @@ Consumer<DexEncodedMethod> keepByteCode) { Map<String, DexEncodedField> fieldMap = new HashMap<>(); for (DexEncodedField field : hostClass.fields()) { - fieldMap.put(toJvmFieldSignature(field.field).asString(), field); + fieldMap.put(toJvmFieldSignature(field.getReference()).asString(), field); } Map<String, DexEncodedMethod> methodMap = new HashMap<>(); for (DexEncodedMethod method : hostClass.methods()) { - methodMap.put(toJvmMethodSignature(method.method).asString(), method); + methodMap.put(toJvmMethodSignature(method.getReference()).asString(), method); } ImmutableList.Builder<KotlinConstructorInfo> notBackedConstructors = ImmutableList.builder(); for (KmConstructor kmConstructor : kmClass.getConstructors()) { @@ -184,7 +184,7 @@ return; } for (DexEncodedField field : hostClass.fields()) { - if (field.field.name.toString().equals(companionObjectName)) { + if (field.getReference().name.toString().equals(companionObjectName)) { field.setKotlinMemberInfo(new KotlinCompanionInfo()); return; } @@ -221,7 +221,10 @@ // Find a companion object. for (DexEncodedField field : clazz.fields()) { if (field.getKotlinMemberInfo().isCompanion()) { - field.getKotlinMemberInfo().asCompanion().rewrite(kmClass, field.field, namingLens); + field + .getKotlinMemberInfo() + .asCompanion() + .rewrite(kmClass, field.getReference(), namingLens); } } // Take all not backed constructors because we will never find them in definitions.
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java index 79b4173..7447bbd 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
@@ -184,7 +184,7 @@ } KotlinPropertyGroup kotlinPropertyGroup = properties.computeIfAbsent(kotlinPropertyInfo, ignored -> new KotlinPropertyGroup()); - if (method.method.proto.returnType == appView.dexItemFactory().voidType) { + if (method.getReference().proto.returnType == appView.dexItemFactory().voidType) { // This is a setter. kotlinPropertyGroup.setSetter(method); } else {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java index f5ce062..008177e 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
@@ -114,8 +114,8 @@ // TODO(b/154348683): Check method for flags to pass in. String finalName = this.name; if (method != null) { - String methodName = method.method.name.toString(); - String rewrittenName = namingLens.lookupName(method.method).toString(); + String methodName = method.getReference().name.toString(); + String rewrittenName = namingLens.lookupName(method.getReference()).toString(); if (!methodName.equals(rewrittenName)) { finalName = rewrittenName; }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java index 974e4a8..2606807 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java
@@ -40,8 +40,8 @@ DexEncodedField field, AppView<?> appView, NamingLens namingLens) { String finalName = name; if (field != null) { - String fieldName = field.field.name.toString(); - String rewrittenName = namingLens.lookupName(field.field).toString(); + String fieldName = field.getReference().name.toString(); + String rewrittenName = namingLens.lookupName(field.getReference()).toString(); if (!fieldName.equals(rewrittenName)) { finalName = rewrittenName; }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java index 2469a54..b0314be 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java
@@ -79,8 +79,8 @@ assert returnType != null; String finalName = name; if (method != null) { - String methodName = method.method.name.toString(); - String rewrittenName = namingLens.lookupName(method.method).toString(); + String methodName = method.getReference().name.toString(); + String rewrittenName = namingLens.lookupName(method.getReference()).toString(); if (!methodName.equals(rewrittenName)) { finalName = rewrittenName; }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java index cc215d5..01a7c2a 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java
@@ -40,7 +40,7 @@ JvmMethodSignature signature = JvmExtensionsKt.getSignature(lambda.function); if (signature != null) { for (DexEncodedMethod method : clazz.methods()) { - if (toJvmMethodSignature(method.method).asString().equals(signature.asString())) { + if (toJvmMethodSignature(method.getReference()).asString().equals(signature.asString())) { method.setKotlinMemberInfo(kotlinFunctionInfo); return new KotlinLambdaInfo(kotlinFunctionInfo, true); }
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 1e3273c..4a5904e 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -182,7 +182,10 @@ if (kotlinMetadata == null || kotlinMetadata.isNotProgramClass()) { return true; } - return kotlinMetadata.methods(method -> method.method.name == fieldName).iterator().hasNext(); + return kotlinMetadata + .methods(method -> method.getReference().name == fieldName) + .iterator() + .hasNext(); } private DexAnnotation createKotlinMetadataAnnotation(
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java index ca1d394..fbfb3bb 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
@@ -110,7 +110,7 @@ KotlinClassMetadata.MultiFileClassFacade kMetadata, String indent) { return indent + "MetaData.MultiFileClassFacade(" - + StringUtils.join(kMetadata.getPartClassNames(), ", ") + + StringUtils.join(", ", kMetadata.getPartClassNames()) + ")"; } @@ -327,16 +327,16 @@ }); String companionObject = kmClass.getCompanionObject(); appendKeyValue( - indent, "enumEntries", sb, "[" + StringUtils.join(kmClass.getEnumEntries(), ",") + "]"); + indent, "enumEntries", sb, "[" + StringUtils.join(",", kmClass.getEnumEntries()) + "]"); appendKeyValue( indent, "companionObject", sb, companionObject == null ? "null" : companionObject); appendKeyValue( indent, "sealedSubclasses", sb, - "[" + StringUtils.join(kmClass.getSealedSubclasses(), ",") + "]"); + "[" + StringUtils.join(",", kmClass.getSealedSubclasses()) + "]"); appendKeyValue( - indent, "nestedClasses", sb, "[" + StringUtils.join(kmClass.getNestedClasses(), ",") + "]"); + indent, "nestedClasses", sb, "[" + StringUtils.join(",", kmClass.getNestedClasses()) + "]"); appendKeyValue( indent, "anonymousObjectOriginName",
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java index 1ac03db..41ff17d 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
@@ -47,11 +47,11 @@ Consumer<DexEncodedMethod> keepByteCode) { Map<String, DexEncodedField> fieldMap = new HashMap<>(); for (DexEncodedField field : clazz.fields()) { - fieldMap.put(toJvmFieldSignature(field.field).asString(), field); + fieldMap.put(toJvmFieldSignature(field.getReference()).asString(), field); } Map<String, DexEncodedMethod> methodMap = new HashMap<>(); for (DexEncodedMethod method : clazz.methods()) { - methodMap.put(toJvmMethodSignature(method.method).asString(), method); + methodMap.put(toJvmMethodSignature(method.getReference()).asString(), method); } return new KotlinPackageInfo( JvmExtensionsKt.getModuleName(kmPackage),
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java index 1b91b62..9ab6c15 100644 --- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -152,11 +152,11 @@ } private void renameDanglingTypesInField(DexEncodedField field) { - renameDanglingType(field.field.type); + renameDanglingType(field.getReference().type); } private void renameDanglingTypesInMethod(DexEncodedMethod method) { - DexProto proto = method.method.proto; + DexProto proto = method.getReference().proto; renameDanglingType(proto.returnType); for (DexType type : proto.parameters.values) { renameDanglingType(type);
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java index 55ed725..bec8073 100644 --- a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
@@ -106,10 +106,10 @@ reservedNames = getOrCreateReservedFieldNamingState(clazz.type); } reservedNames.markReservedDirectly( - reservedName, field.field.name, field.field.type); + reservedName, field.getReference().name, field.getReference().type); // TODO(b/148846065): Consider lazily computing the renaming on actual lookups. - if (reservedName != field.field.name) { - renaming.put(field.field, reservedName); + if (reservedName != field.getReference().name) { + renaming.put(field.getReference(), reservedName); } } } @@ -135,8 +135,8 @@ clazz -> { for (DexEncodedField field : clazz.fields()) { DexString reservedName = strategy.getReservedName(field, clazz); - if (reservedName != null && reservedName != field.field.name) { - renaming.put(field.field, reservedName); + if (reservedName != null && reservedName != field.getReference().name) { + renaming.put(field.getReference(), reservedName); } } }); @@ -270,8 +270,10 @@ return; } DexEncodedField definition = appView.appInfo().resolveFieldOn(holder, field).getResolvedField(); - if (definition != null && definition.field != field && renaming.containsKey(definition.field)) { - renaming.put(field, renaming.get(definition.field)); + if (definition != null + && definition.getReference() != field + && renaming.containsKey(definition.getReference())) { + renaming.put(field, renaming.get(definition.getReference())); } }
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java index 2d9a19d..e0de1d5 100644 --- a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java +++ b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
@@ -74,7 +74,7 @@ private void decoupleIdentifierNameStringInStaticField(DexEncodedField encodedField) { assert encodedField.accessFlags.isStatic(); - if (!identifierNameStrings.containsKey(encodedField.field)) { + if (!identifierNameStrings.containsKey(encodedField.getReference())) { return; } DexValueString staticValue = encodedField.getStaticValue().asDexValueString();
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringUtils.java b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringUtils.java index 01157b9..3e4078b 100644 --- a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringUtils.java +++ b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringUtils.java
@@ -378,9 +378,9 @@ private static DexField inferFieldInHolder(DexClass holder, String name, DexType fieldType) { for (DexEncodedField encodedField : holder.fields()) { - if (encodedField.field.name.toString().equals(name) - && (fieldType == null || encodedField.field.type == fieldType)) { - return encodedField.field; + if (encodedField.getReference().name.toString().equals(name) + && (fieldType == null || encodedField.getReference().type == fieldType)) { + return encodedField.getReference(); } } return null; @@ -388,8 +388,8 @@ private static DexMethod inferMethodNameInHolder(DexClass holder, String name) { for (DexEncodedMethod encodedMethod : holder.methods()) { - if (encodedMethod.method.name.toString().equals(name)) { - return encodedMethod.method; + if (encodedMethod.getReference().name.toString().equals(name)) { + return encodedMethod.getReference(); } } return null; @@ -399,9 +399,9 @@ DexClass holder, String name, DexTypeList arguments) { assert arguments != null; for (DexEncodedMethod encodedMethod : holder.methods()) { - if (encodedMethod.method.name.toString().equals(name) - && encodedMethod.method.proto.parameters.equals(arguments)) { - return encodedMethod.method; + if (encodedMethod.getReference().name.toString().equals(name) + && encodedMethod.getReference().proto.parameters.equals(arguments)) { + return encodedMethod.getReference(); } } return null;
diff --git a/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java b/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java index 0f5924d..3ba2467 100644 --- a/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java
@@ -483,7 +483,8 @@ boolean differentName = implementedMethod.getName() != virtualMethod.getName(); if (differentName && MethodJavaSignatureEquivalence.getEquivalenceIgnoreName() - .equivalent(implementedMethod.method, virtualMethod.method)) { + .equivalent( + implementedMethod.getReference(), virtualMethod.getReference())) { InterfaceMethodGroupState interfaceMethodGroupState = globalStateMap.computeIfAbsent( definitionEquivalence.wrap(implementedMethod),
diff --git a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java index eb4e9ca..a51edde 100644 --- a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java +++ b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
@@ -96,7 +96,7 @@ // If the method does not have a direct renaming, return the resolutions mapping. ResolutionResult resolutionResult = appView.appInfo().unsafeResolveMethodDueToDexFormat(method); if (resolutionResult.isSingleResolution()) { - return renaming.getOrDefault(resolutionResult.getSingleTarget().method, method.name); + return renaming.getOrDefault(resolutionResult.getSingleTarget().getReference(), method.name); } // If resolution fails, the method must be renamed consistently with the targets that give rise // to the failure. @@ -104,8 +104,9 @@ List<DexEncodedMethod> targets = new ArrayList<>(); resolutionResult.asFailedResolution().forEachFailureDependency(targets::add); if (!targets.isEmpty()) { - DexString firstRename = renaming.get(targets.get(0).method); - assert targets.stream().allMatch(target -> renaming.get(target.method) == firstRename); + DexString firstRename = renaming.get(targets.get(0).getReference()); + assert targets.stream() + .allMatch(target -> renaming.get(target.getReference()) == firstRename); if (firstRename != null) { return firstRename; } @@ -138,7 +139,7 @@ // If we can resolve `item`, then the renaming for `item` and its resolution should be the // same. DexEncodedMethod resolvedMethod = resolution.asSingleResolution().getResolvedMethod(); - assert lookupName(method) == lookupName(resolvedMethod.method); + assert lookupName(method) == lookupName(resolvedMethod.getReference()); return true; } @@ -162,7 +163,7 @@ .asFailedResolution() .forEachFailureDependency( failureDependence -> { - assert lookupName(method) == lookupName(failureDependence.method); + assert lookupName(method) == lookupName(failureDependence.getReference()); }); return true; }
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 c00993f..a542a2f 100644 --- a/src/main/java/com/android/tools/r8/naming/Minifier.java +++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -260,22 +260,24 @@ if (!allowMemberRenaming(holder) || holder.accessFlags.isAnnotation() || method.accessFlags.isConstructor() - || !appView.appInfo().isMinificationAllowed(method.method)) { - return method.method.name; + || !appView.appInfo().isMinificationAllowed(method.getReference())) { + return method.getReference().name; } if (desugaredLibraryRenaming && method.isLibraryMethodOverride().isTrue() - && appView.rewritePrefix.hasRewrittenTypeInSignature(method.method.proto, appView)) { + && appView.rewritePrefix.hasRewrittenTypeInSignature( + method.getReference().proto, appView)) { // With desugared library, call-backs names are reserved here. - return method.method.name; + return method.getReference().name; } return null; } @Override public DexString getReservedName(DexEncodedField field, DexClass holder) { - if (holder.isLibraryClass() || !appView.appInfo().isMinificationAllowed(field.field)) { - return field.field.name; + if (holder.isLibraryClass() + || !appView.appInfo().isMinificationAllowed(field.getReference())) { + return field.getReference().name; } return null; }
diff --git a/src/main/java/com/android/tools/r8/naming/NamingLens.java b/src/main/java/com/android/tools/r8/naming/NamingLens.java index bdd0e70..b6e94ee 100644 --- a/src/main/java/com/android/tools/r8/naming/NamingLens.java +++ b/src/main/java/com/android/tools/r8/naming/NamingLens.java
@@ -166,14 +166,14 @@ } for (DexEncodedField field : clazz.fields()) { - DexField newField = lookupField(field.field, dexItemFactory); + DexField newField = lookupField(field.getReference(), dexItemFactory); boolean referencesChanged = references.add(newField); assert referencesChanged : "Duplicate definition of field `" + newField.toSourceString() + "`"; } for (DexEncodedMethod method : clazz.methods()) { - DexMethod newMethod = lookupMethod(method.method, dexItemFactory); + DexMethod newMethod = lookupMethod(method.getReference(), dexItemFactory); boolean referencesChanged = references.add(newMethod); assert referencesChanged : "Duplicate definition of method `" + newMethod.toSourceString() + "`";
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 b75956e..a8e299a 100644 --- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -5,6 +5,7 @@ package com.android.tools.r8.naming; import static com.android.tools.r8.graph.DexApplication.classesWithDeterministicOrder; +import static com.android.tools.r8.utils.IterableUtils.fromMethod; import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; @@ -51,7 +52,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.function.BiPredicate; -import java.util.function.Consumer; import java.util.function.Predicate; /** @@ -99,19 +99,17 @@ timing.begin("MappingInterfaces"); Set<DexClass> interfaces = new TreeSet<>(Comparator.comparing(DexClass::getType)); - Consumer<DexClass> consumer = - clazz -> { - if (clazz.isInterface()) { - // Only visit top level interfaces because computeMapping will visit the hierarchy. - if (clazz.interfaces.isEmpty()) { - computeMapping(clazz.type, nonPrivateMembers, notMappedReferences, subtypingInfo); - } - interfaces.add(clazz); - } - }; // For union-find of interface methods we also need to add the library types above live types. - appInfo.forEachTypeInHierarchyOfLiveProgramClasses(consumer); - appInfo.forEachReferencedClasspathClass(consumer::accept); + appInfo.forEachReachableInterface( + iFace -> { + assert iFace.isInterface(); + interfaces.add(iFace); + if (iFace.interfaces.isEmpty()) { + computeMapping(iFace.type, nonPrivateMembers, notMappedReferences, subtypingInfo); + } + }, + fromMethod(appInfo::forEachReferencedClasspathClass, DexClass::getType)); + assert nonPrivateMembers.isEmpty(); timing.end(); @@ -504,12 +502,12 @@ @Override public DexString getReservedName(DexEncodedMethod method, DexClass holder) { - return getReservedName(method, method.method.name, holder); + return getReservedName(method, method.getReference().name, holder); } @Override public DexString getReservedName(DexEncodedField field, DexClass holder) { - return getReservedName(field, field.field.name, holder); + return getReservedName(field, field.getReference().name, holder); } private DexString getReservedName(DexDefinition definition, DexString name, DexClass holder) {
diff --git a/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java b/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java index 83fa84e..e809317 100644 --- a/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java +++ b/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java
@@ -45,7 +45,7 @@ private DexString getRenaming(DexType type) { if (type == factory.recordType) { - return factory.r8RecordType.descriptor; + return factory.recordTagType.descriptor; } return null; } @@ -77,7 +77,7 @@ @Override public DexString lookupDescriptorForJavaTypeName(String typeName) { if (typeName.equals(factory.recordType.toSourceString())) { - return factory.r8RecordType.descriptor; + return factory.recordTagType.descriptor; } return namingLens.lookupDescriptorForJavaTypeName(typeName); }
diff --git a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java index a675776..dd67f3a 100644 --- a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java +++ b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
@@ -167,14 +167,16 @@ if (accessFlags.isPackagePrivate()) { // If we publicize a package private method we have to ensure there is no overrides of it. We - // could potentially publicize a method if it only has package-private overrides, but for know - // we just check if it is seen below. - // Note that we will not publize private methods if there exists a package-private override, - // and there is therefore no need to check the hierarchy above. + // could potentially publicize a method if it only has package-private overrides. + // TODO(b/182136236): See if we can break the hierarchy for clusters. MemberPool<DexMethod> memberPool = methodPoolCollection.get(method.getHolder()); Wrapper<DexMethod> methodKey = MethodSignatureEquivalence.get().wrap(method.getReference()); - if (memberPool.hasSeenStrictlyBelow(methodKey) - && appView.options().enablePackagePrivateAwarePublicization) { + if (memberPool.below( + methodKey, + false, + true, + (clazz, ignored) -> + !method.getContextType().getPackageName().equals(clazz.getType().getPackageName()))) { return false; } doPublicize(method);
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java index 04a24b6..2b9252f 100644 --- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java +++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -188,11 +188,11 @@ DexEncodedMethod target = lookupTarget.apply(method); // TODO(b/128404854) Rebind to the lowest library class or program class. For now we allow // searching in library for methods, but this should be done on classpath instead. - if (target == null || target.method == method) { + if (target == null || target.getReference() == method) { return; } DexClass targetClass = appView.definitionFor(target.getHolderType()); - DexMethod targetMethod = target.method; + DexMethod targetMethod = target.getReference(); if (originalClass.isProgramClass()) { // In Java bytecode, it is only possible to target interface methods that are in one of // the immediate super-interfaces via a super-invocation (see @@ -235,7 +235,7 @@ target.toForwardingMethod(bridgeHolder, appView); bridgeHolder.addMethod(bridgeMethodDefinition); } - assert lookupTarget.apply(method).method == bridgeMethod; + assert lookupTarget.apply(method).getReference() == bridgeMethod; } }); } @@ -267,7 +267,7 @@ assert bridgeHolder != null; assert bridgeHolder != targetClass; bridges.accept(bridgeHolder, method, target); - return target.method.withHolder(bridgeHolder.getType(), appView.dexItemFactory()); + return target.getReference().withHolder(bridgeHolder.getType(), appView.dexItemFactory()); } private DexProgramClass findHolderForInterfaceMethodBridge(DexProgramClass clazz, DexType iface) { @@ -316,9 +316,9 @@ findHolderForVisibilityBridge(originalClass, targetClass, packageDescriptor); assert bridgeHolder != null; bridges.accept(bridgeHolder, method, target); - return target.method.withHolder(bridgeHolder.getType(), appView.dexItemFactory()); + return target.getReference().withHolder(bridgeHolder.getType(), appView.dexItemFactory()); } - return target.method; + return target.getReference(); } private DexProgramClass findHolderForVisibilityBridge(
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java index 171dcbe..4310236 100644 --- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java +++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.optimize; -import static com.android.tools.r8.graph.GraphLens.NestedGraphLens.mapVirtualInterfaceInvocationTypes; +import static com.android.tools.r8.graph.NestedGraphLens.mapVirtualInterfaceInvocationTypes; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexField;
diff --git a/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java b/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java index 8ea4e1f..322ccb1 100644 --- a/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java +++ b/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java
@@ -8,10 +8,8 @@ import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.GraphLens; -import com.android.tools.r8.graph.GraphLens.NestedGraphLens; +import com.android.tools.r8.graph.NestedGraphLens; import com.android.tools.r8.ir.code.Invoke.Type; -import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import java.util.Set; @@ -21,13 +19,7 @@ private final Set<DexMethod> publicizedMethods; private PublicizerLens(AppView<?> appView, Set<DexMethod> publicizedMethods) { - super( - ImmutableMap.of(), - ImmutableMap.of(), - new EmptyBidirectionalOneToOneMap<>(), - new EmptyBidirectionalOneToOneMap<>(), - appView.graphLens(), - appView.dexItemFactory()); + super(appView, EMPTY_FIELD_MAP, EMPTY_METHOD_MAP, EMPTY_TYPE_MAP); this.appView = appView; this.publicizedMethods = publicizedMethods; }
diff --git a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java index 96dd07b..f073314 100644 --- a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java +++ b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
@@ -87,7 +87,10 @@ if (targetMethod != null && targetMethod.accessFlags.isPublic()) { if (Log.ENABLED) { Log.info( - getClass(), "Removing visibility forwarding %s -> %s", method, targetMethod.method); + getClass(), + "Removing visibility forwarding %s -> %s", + method, + targetMethod.getReference()); } return true; }
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 ea4ee0e..69c59b5 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
@@ -140,7 +140,7 @@ for (DexEncodedMethod method : subclass.virtualMethods()) { BridgeInfo bridgeInfo = method.getOptimizationInfo().getBridgeInfo(); if (bridgeInfo != null) { - candidates.add(equivalence.wrap(method.method)); + candidates.add(equivalence.wrap(method.getReference())); } } }
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingResult.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingResult.java index 4439aea..e1311d5 100644 --- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingResult.java +++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingResult.java
@@ -23,7 +23,7 @@ // Mapping from non-hoisted bridge methods to hoisted bridge methods. private final MutableBidirectionalManyToOneRepresentativeMap<DexMethod, DexMethod> - bridgeToHoistedBridgeMap = new BidirectionalManyToOneRepresentativeHashMap<>(); + bridgeToHoistedBridgeMap = BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap(); BridgeHoistingResult(AppView<AppInfoWithLiveness> appView) { this.appView = appView;
diff --git a/src/main/java/com/android/tools/r8/references/MethodReference.java b/src/main/java/com/android/tools/r8/references/MethodReference.java index 9ff0649..fc8f183 100644 --- a/src/main/java/com/android/tools/r8/references/MethodReference.java +++ b/src/main/java/com/android/tools/r8/references/MethodReference.java
@@ -77,7 +77,7 @@ public String getMethodDescriptor() { return StringUtils.join( - ListUtils.map(getFormalTypes(), TypeReference::getDescriptor), "", BraceType.PARENS) + "", ListUtils.map(getFormalTypes(), TypeReference::getDescriptor), BraceType.PARENS) + (getReturnType() == null ? "V" : getReturnType().getDescriptor()); }
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java index e6d16eb..64fe0eb 100644 --- a/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java +++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
@@ -10,7 +10,7 @@ import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexReference; import com.android.tools.r8.graph.DexType; -import com.android.tools.r8.graph.GraphLens.NestedGraphLens; +import com.android.tools.r8.graph.NestedGraphLens; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.utils.IterableUtils; import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap; @@ -22,23 +22,17 @@ public class RepackagingLens extends NestedGraphLens { - private final BiMap<DexType, DexType> originalTypes; + private final BiMap<DexType, DexType> newTypes; private final Map<String, String> packageRenamings; private RepackagingLens( AppView<AppInfoWithLiveness> appView, BidirectionalOneToOneMap<DexField, DexField> newFieldSignatures, - BidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures, - BiMap<DexType, DexType> originalTypes, + BidirectionalOneToOneMap<DexMethod, DexMethod> newMethodSignatures, + BiMap<DexType, DexType> newTypes, Map<String, String> packageRenamings) { - super( - originalTypes.inverse(), - originalMethodSignatures.getInverseOneToOneMap().getForwardMap(), - newFieldSignatures, - originalMethodSignatures, - appView.graphLens(), - appView.dexItemFactory()); - this.originalTypes = originalTypes; + super(appView, newFieldSignatures, newMethodSignatures, newTypes); + this.newTypes = newTypes; this.packageRenamings = packageRenamings; } @@ -49,7 +43,7 @@ @Override public DexType getOriginalType(DexType type) { - DexType previous = originalTypes.getOrDefault(type, type); + DexType previous = newTypes.inverse().getOrDefault(type, type); return getPrevious().getOriginalType(previous); } @@ -73,7 +67,7 @@ } private boolean isSimpleTypeRenamingOrEqual(DexType from, DexType to) { - return from == to || originalTypes.get(to) == from; + return from == to || newTypes.get(from) == to; } private boolean isSimpleTypeRenamingOrEqual(DexMember<?, ?> from, DexMember<?, ?> to) { @@ -82,16 +76,16 @@ } return IterableUtils.testPairs( this::isSimpleTypeRenamingOrEqual, - from.getReferencedBaseTypes(dexItemFactory), - to.getReferencedBaseTypes(dexItemFactory)); + from.getReferencedBaseTypes(dexItemFactory()), + to.getReferencedBaseTypes(dexItemFactory())); } public static class Builder { - protected final BiMap<DexType, DexType> originalTypes = HashBiMap.create(); + protected final BiMap<DexType, DexType> newTypes = HashBiMap.create(); protected final MutableBidirectionalOneToOneMap<DexField, DexField> newFieldSignatures = new BidirectionalOneToOneHashMap<>(); - protected final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures = + protected final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> newMethodSignatures = new BidirectionalOneToOneHashMap<>(); public void recordMove(DexField from, DexField to) { @@ -99,18 +93,18 @@ } public void recordMove(DexMethod from, DexMethod to) { - originalMethodSignatures.put(to, from); + newMethodSignatures.put(from, to); } public void recordMove(DexType from, DexType to) { - originalTypes.put(to, from); + newTypes.put(from, to); } public RepackagingLens build( AppView<AppInfoWithLiveness> appView, Map<String, String> packageRenamings) { - assert !originalTypes.isEmpty(); + assert !newTypes.isEmpty(); return new RepackagingLens( - appView, newFieldSignatures, originalMethodSignatures, originalTypes, packageRenamings); + appView, newFieldSignatures, newMethodSignatures, newTypes, packageRenamings); } } }
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 b64646d..4123c10 100644 --- a/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java +++ b/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
@@ -64,7 +64,7 @@ DexEncodedMethod method = virtualMethods.get(i); if (scope.addMethodIfMoreVisible(method) != AddMethodIfMoreVisibleResult.NOT_ADDED || !method.accessFlags.isAbstract() - || appView.appInfo().isPinned(method.method)) { + || appView.appInfo().isPinned(method.getReference())) { if (methods != null) { methods.add(method); } @@ -76,7 +76,7 @@ } } if (Log.ENABLED) { - Log.debug(getClass(), "Removing abstract method %s.", method.method); + Log.debug(getClass(), "Removing abstract method %s.", method.getReference()); } } }
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java index 057a80f..34c11ee 100644 --- a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java +++ b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
@@ -254,7 +254,7 @@ boolean liveGetter = definition .getMethodCollection() - .hasVirtualMethods(method -> method.method.name == original.name); + .hasVirtualMethods(method -> method.getReference().name == original.name); return liveGetter ? original : null; }
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 b186a52..4622786 100644 --- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java +++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -59,6 +59,7 @@ import com.android.tools.r8.utils.WorkList; import com.android.tools.r8.utils.collections.ProgramMethodSet; import com.android.tools.r8.utils.structural.Ordered; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import it.unimi.dsi.fastutil.ints.Int2ReferenceMap; import it.unimi.dsi.fastutil.objects.Object2BooleanMap; @@ -662,7 +663,13 @@ } public void forEachReachableInterface(Consumer<DexClass> consumer) { + forEachReachableInterface(consumer, ImmutableList.of()); + } + + public void forEachReachableInterface( + Consumer<DexClass> consumer, Iterable<DexType> additionalPaths) { WorkList<DexType> worklist = WorkList.newIdentityWorkList(); + worklist.addIfNotSeen(additionalPaths); worklist.addIfNotSeen(objectAllocationInfoCollection.getInstantiatedLambdaInterfaces()); for (DexProgramClass clazz : classes()) { worklist.addIfNotSeen(clazz.type); @@ -676,10 +683,7 @@ if (definition.isInterface()) { consumer.accept(definition); } - if (definition.superType != null) { - worklist.addIfNotSeen(definition.superType); - } - worklist.addIfNotSeen(definition.interfaces.values); + definition.forEachImmediateSupertype(worklist::addIfNotSeen); } } @@ -727,7 +731,7 @@ } assert clazz.isInterface(); for (DexEncodedMethod method : clazz.virtualMethods()) { - if (method.method.name == callSite.methodName && method.accessFlags.isAbstract()) { + if (method.getReference().name == callSite.methodName && method.accessFlags.isAbstract()) { result.add(method); } } @@ -806,7 +810,7 @@ public boolean isFieldRead(DexEncodedField encodedField) { assert checkIfObsolete(); - DexField field = encodedField.field; + DexField field = encodedField.getReference(); FieldAccessInfo info = getFieldAccessInfoCollection().get(field); if (info != null && info.isRead()) { return true; @@ -820,12 +824,13 @@ public boolean isFieldWritten(DexEncodedField encodedField) { assert checkIfObsolete(); - return isFieldWrittenByFieldPutInstruction(encodedField) || isPinned(encodedField.field); + return isFieldWrittenByFieldPutInstruction(encodedField) + || isPinned(encodedField.getReference()); } public boolean isFieldWrittenByFieldPutInstruction(DexEncodedField encodedField) { assert checkIfObsolete(); - DexField field = encodedField.field; + DexField field = encodedField.getReference(); FieldAccessInfo info = getFieldAccessInfoCollection().get(field); if (info != null && info.isWritten()) { // The field is written directly by the program itself. @@ -838,7 +843,7 @@ public boolean isFieldOnlyWrittenInMethod(DexEncodedField field, DexEncodedMethod method) { assert checkIfObsolete(); assert isFieldWritten(field) : "Expected field `" + field.toSourceString() + "` to be written"; - if (isPinned(field.field)) { + if (isPinned(field.getReference())) { return false; } return isFieldOnlyWrittenInMethodIgnoringPinning(field, method); @@ -848,7 +853,7 @@ DexEncodedField field, DexEncodedMethod method) { assert checkIfObsolete(); assert isFieldWritten(field) : "Expected field `" + field.toSourceString() + "` to be written"; - FieldAccessInfo fieldAccessInfo = getFieldAccessInfoCollection().get(field.field); + FieldAccessInfo fieldAccessInfo = getFieldAccessInfoCollection().get(field.getReference()); return fieldAccessInfo != null && fieldAccessInfo.isWritten() && !fieldAccessInfo.isWrittenOutside(method); @@ -857,10 +862,10 @@ public boolean isInstanceFieldWrittenOnlyInInstanceInitializers(DexEncodedField field) { assert checkIfObsolete(); assert isFieldWritten(field) : "Expected field `" + field.toSourceString() + "` to be written"; - if (isPinned(field.field)) { + if (isPinned(field.getReference())) { return false; } - FieldAccessInfo fieldAccessInfo = getFieldAccessInfoCollection().get(field.field); + FieldAccessInfo fieldAccessInfo = getFieldAccessInfoCollection().get(field.getReference()); if (fieldAccessInfo == null || !fieldAccessInfo.isWritten()) { return false; } @@ -995,7 +1000,7 @@ DexProgramClass clazz = asProgramClassOrNull(definitionFor(type)); if (clazz != null) { for (DexEncodedMethod method : clazz.directMethods()) { - if (method.isInstanceInitializer() && isPinned(method.method)) { + if (method.isInstanceInitializer() && isPinned(method.getReference())) { return true; } } @@ -1267,7 +1272,7 @@ if (refinedReceiverClass.isProgramClass()) { DexClassAndMethod clazzAndMethod = resolution.lookupVirtualDispatchTarget(refinedReceiverClass.asProgramClass(), this); - if (clazzAndMethod == null || isPinned(clazzAndMethod.getDefinition().method)) { + if (clazzAndMethod == null || isPinned(clazzAndMethod.getDefinition().getReference())) { // TODO(b/150640456): We should maybe only consider program methods. return DexEncodedMethod.SENTINEL; } @@ -1279,7 +1284,7 @@ // implementation, but we use this for library modelling. DexEncodedMethod resolvedMethod = resolution.getResolvedMethod(); DexEncodedMethod targetOnReceiver = - refinedReceiverClass.lookupVirtualMethod(resolvedMethod.method); + refinedReceiverClass.lookupVirtualMethod(resolvedMethod.getReference()); if (targetOnReceiver != null && isOverriding(resolvedMethod, targetOnReceiver)) { return targetOnReceiver; }
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java index f032832..03611d6 100644 --- a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java +++ b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
@@ -54,7 +54,7 @@ } // When compiling for dex, we can't use wide fields since we've only allocated a single // register for the out-value of each ClassInit instruction - if (staticField.field.type.isWideType()) { + if (staticField.getReference().type.isWideType()) { continue; } if (encodedClinitField == null) { @@ -90,7 +90,7 @@ d8R8Synthesized); clazz.appendStaticField(encodedClinitField); } - lensBuilder.map(type, encodedClinitField.field); + lensBuilder.map(type, encodedClinitField.getReference()); } private boolean isMinimumRequiredVisibility(
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 e818526..331466b 100644 --- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java +++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -929,17 +929,17 @@ } // Check if we have previously created a FieldAccessInfo object for the field definition. - info = fieldAccessInfoCollection.get(encodedField.field); + info = fieldAccessInfoCollection.get(encodedField.getReference()); // If not, we must create one. if (info == null) { - info = new FieldAccessInfoImpl(encodedField.field); - fieldAccessInfoCollection.extend(encodedField.field, info); + info = new FieldAccessInfoImpl(encodedField.getReference()); + fieldAccessInfoCollection.extend(encodedField.getReference(), info); } // If `field` is an indirect reference, then create a mapping for it, such that we don't have // to resolve the field the next time we see the reference. - if (field != encodedField.field) { + if (field != encodedField.getReference()) { fieldAccessInfoCollection.extend(field, info); } } else if (info == MISSING_FIELD_ACCESS_INFO) { @@ -2122,7 +2122,7 @@ // targets another default method in the same interface (see testInvokeSpecialToDefault- // Method). In a class, that would lead to a verification error. if (encodedMethod.isNonPrivateVirtualMethod() - && virtualMethodsTargetedByInvokeDirect.add(encodedMethod.method)) { + && virtualMethodsTargetedByInvokeDirect.add(encodedMethod.getReference())) { workList.enqueueMarkMethodLiveAction(method, context, reason); } } @@ -2442,7 +2442,7 @@ markVirtualMethodAsLive( resolutionMethod, graphReporter.reportReachableMethodAsLive( - resolutionMethod.getDefinition().method, resolutionMethod)); + resolutionMethod.getDefinition().getReference(), resolutionMethod)); return; } // Otherwise, we set the initial holder type to be the holder of the reachable method, which @@ -2456,7 +2456,7 @@ lookup, programMethod -> graphReporter.reportReachableMethodAsLive( - resolutionMethod.getDefinition().method, programMethod)); + resolutionMethod.getDefinition().getReference(), programMethod)); } } @@ -2474,7 +2474,9 @@ // Note: It would be reasonable to not process methods already seen during the marking of // program usages, but that would cause the methods to not be marked as library overrides. markLibraryOrClasspathOverrideLive( - instantiation, libraryClass, appInfo.resolveMethodOn(libraryClass, method.method)); + instantiation, + libraryClass, + appInfo.resolveMethodOn(libraryClass, method.getReference())); // Due to API conversion, some overrides can be hidden since they will be rewritten. See // class comment of DesugaredLibraryAPIConverter and vivifiedType logic. @@ -2482,11 +2484,12 @@ // maintains the library override. In the second enqueuer phase, the signature has been // desugared, and the second resolution maintains the the library override. if (instantiation.isClass() - && appView.rewritePrefix.hasRewrittenTypeInSignature(method.method.proto, appView)) { + && appView.rewritePrefix.hasRewrittenTypeInSignature( + method.getReference().proto, appView)) { DexMethod methodToResolve = DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature( - method.method, method.getHolderType(), appView); - assert methodToResolve != method.method; + method.getReference(), method.getHolderType(), appView); + assert methodToResolve != method.getReference(); markLibraryOrClasspathOverrideLive( instantiation, libraryClass, @@ -2514,7 +2517,7 @@ if (instantiation.isClass()) { // TODO(b/149976493): We need to mark these for lambdas too! markOverridesAsLibraryMethodOverrides( - instantiation.asClass(), lookup.asMethodTarget().getDefinition().method); + instantiation.asClass(), lookup.asMethodTarget().getDefinition().getReference()); } } @@ -2688,7 +2691,7 @@ } public boolean isFieldReferenced(DexEncodedField field) { - FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field.field); + FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field.getReference()); return info != null; } @@ -2834,7 +2837,7 @@ target, programMethod -> graphReporter.reportReachableMethodAsLive( - resolvedMethod.method, programMethod))); + resolvedMethod.getReference(), programMethod))); } private void markVirtualDispatchTargetAsLive( @@ -2874,7 +2877,7 @@ method -> { DexProgramClass clazz = getProgramClassOrNull(method.getHolderType(), context); if (clazz != null) { - failedMethodResolutionTargets.add(method.method); + failedMethodResolutionTargets.add(method.getReference()); markMethodAsTargeted(new ProgramMethod(clazz, method), reason); } }); @@ -2920,7 +2923,7 @@ // If invoke target is invalid (inaccessible or not an instance-method) record it and stop. DexClassAndMethod target = resolution.lookupInvokeSuperTarget(from.getHolder(), appInfo); if (target == null) { - failedMethodResolutionTargets.add(resolution.getResolvedMethod().method); + failedMethodResolutionTargets.add(resolution.getResolvedMethod().getReference()); return; } @@ -2961,7 +2964,7 @@ MainDexInfo.Builder builder = appView.appInfo().getMainDexInfo().builder(); liveTypes.getItems().forEach(builder::addRoot); if (mode.isInitialMainDexTracing()) { - liveMethods.getItems().forEach(method -> builder.addRoot(method.method)); + liveMethods.getItems().forEach(method -> builder.addRoot(method.getReference())); } else { assert appView.appInfo().getMainDexInfo().isTracedMethodRootsCleared() || mode.isGenerateMainDexList(); @@ -3115,7 +3118,7 @@ } void addLiveMethod(ProgramMethod method) { - DexMethod signature = method.getDefinition().method; + DexMethod signature = method.getDefinition().getReference(); assert !liveMethods.containsKey(signature); liveMethods.put(signature, method); } @@ -3399,7 +3402,7 @@ : "Expected type to be in live non-program types: " + clazz; for (DexEncodedField field : clazz.fields()) { if (clazz.isNotProgramClass() || isFieldReferenced(field)) { - assert verifyReferencedType(field.field.type, worklist, app); + assert verifyReferencedType(field.getReference().type, worklist, app); } } for (DexEncodedMethod method : clazz.methods()) { @@ -3412,8 +3415,8 @@ private boolean verifyReferencedMethod( DexEncodedMethod method, WorkList<DexClass> worklist, DexApplication app) { - assert verifyReferencedType(method.method.proto.returnType, worklist, app); - for (DexType param : method.method.proto.parameters.values) { + assert verifyReferencedType(method.getReference().proto.returnType, worklist, app); + for (DexType param : method.getReference().proto.parameters.values) { assert verifyReferencedType(param, worklist, app); } return true; @@ -3644,16 +3647,19 @@ return; } if (methodToKeep != singleTarget - && !syntheticInterfaceMethodBridges.containsKey(methodToKeep.getDefinition().method)) { - syntheticInterfaceMethodBridges.put(methodToKeep.getDefinition().method, methodToKeep); - assert null == methodToKeep.getHolder().lookupMethod(methodToKeep.getDefinition().method); + && !syntheticInterfaceMethodBridges.containsKey( + methodToKeep.getDefinition().getReference())) { + syntheticInterfaceMethodBridges.put( + methodToKeep.getDefinition().getReference(), methodToKeep); + assert null + == methodToKeep.getHolder().lookupMethod(methodToKeep.getDefinition().getReference()); if (singleTargetMethod.isLibraryMethodOverride().isTrue()) { methodToKeep.getDefinition().setLibraryMethodOverride(OptionalBool.TRUE); } DexProgramClass singleTargetHolder = singleTarget.getHolder(); assert singleTargetHolder.isInterface(); markVirtualMethodAsReachable( - singleTargetMethod.method, + singleTargetMethod.getReference(), singleTargetHolder.isInterface(), singleTarget, graphReporter.fakeReportShouldNotBeUsed()); @@ -3748,7 +3754,7 @@ DexProgramClass current = worklist.removeFirst(); assert visited.contains(current); - if (current.lookupVirtualMethod(method.method) != null) { + if (current.lookupVirtualMethod(method.getReference()) != null) { continue; } @@ -4482,7 +4488,7 @@ DexEncodedMethod target = holder.lookupDirectMethod(method); if (target != null) { // There is no dispatch on annotations, so only keep what is directly referenced. - if (target.method == method) { + if (target.getReference() == method) { markDirectStaticOrConstructorMethodAsLive( new ProgramMethod(holder, target), KeepReason.referencedInAnnotation(annotationHolder)); @@ -4490,7 +4496,7 @@ } else { target = holder.lookupVirtualMethod(method); // There is no dispatch on annotations, so only keep what is directly referenced. - if (target != null && target.method == method) { + if (target != null && target.getReference() == method) { markMethodAsTargeted( new ProgramMethod(holder, target), KeepReason.referencedInAnnotation(annotationHolder));
diff --git a/src/main/java/com/android/tools/r8/shaking/GraphReporter.java b/src/main/java/com/android/tools/r8/shaking/GraphReporter.java index 6459b7f..ac0d153 100644 --- a/src/main/java/com/android/tools/r8/shaking/GraphReporter.java +++ b/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
@@ -136,7 +136,7 @@ } KeepRuleGraphNode ruleNode = getKeepRuleGraphNode(precondition, rule); EdgeKind edgeKind = reportPrecondition(ruleNode); - return reportEdge(ruleNode, getMethodGraphNode(method.method), edgeKind); + return reportEdge(ruleNode, getMethodGraphNode(method.getReference()), edgeKind); } KeepReasonWitness reportKeepMethod( @@ -157,7 +157,7 @@ } KeepRuleGraphNode ruleNode = getKeepRuleGraphNode(precondition, rule); EdgeKind edgeKind = reportPrecondition(ruleNode); - return reportEdge(ruleNode, getFieldGraphNode(field.field), edgeKind); + return reportEdge(ruleNode, getFieldGraphNode(field.getReference()), edgeKind); } KeepReasonWitness reportKeepField( @@ -259,10 +259,11 @@ public KeepReasonWitness reportReachableMethodAsLive( DexMethod overriddenMethod, ProgramMethod derivedMethod) { - if (keptGraphConsumer != null && overriddenMethod != derivedMethod.getDefinition().method) { + if (keptGraphConsumer != null + && overriddenMethod != derivedMethod.getDefinition().getReference()) { return reportEdge( getMethodGraphNode(overriddenMethod), - getMethodGraphNode(derivedMethod.getDefinition().method), + getMethodGraphNode(derivedMethod.getDefinition().getReference()), EdgeKind.OverridingMethod); } return KeepReasonWitness.INSTANCE; @@ -276,7 +277,7 @@ if (keptGraphConsumer != null && instantiation.isClass()) { return reportEdge( getClassGraphNode(instantiation.asClass().type), - getMethodGraphNode(derivedMethod.getDefinition().method), + getMethodGraphNode(derivedMethod.getDefinition().getReference()), EdgeKind.IsLibraryMethod); } return KeepReasonWitness.INSTANCE; @@ -299,8 +300,8 @@ return KeepReasonWitness.INSTANCE; } return reportEdge( - getMethodGraphNode(definition.method), - getMethodGraphNode(implementation.method), + getMethodGraphNode(definition.getReference()), + getMethodGraphNode(implementation.getReference()), EdgeKind.CompanionMethod); } @@ -375,14 +376,14 @@ // TODO(b/120959039): This should be dead code once no library classes are ever enqueued. return KeepReasonWitness.INSTANCE; } - return registerEdge(getMethodGraphNode(method.method), reason); + return registerEdge(getMethodGraphNode(method.getReference()), reason); } public KeepReasonWitness registerField(DexEncodedField field, KeepReason reason) { if (skipReporting(reason)) { return KeepReasonWitness.INSTANCE; } - return registerEdge(getFieldGraphNode(field.field), reason); + return registerEdge(getFieldGraphNode(field.getReference()), reason); } private KeepReasonWitness registerEdge(GraphNode target, KeepReason reason) {
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 e843d0d..aa6844e 100644 --- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java +++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
@@ -235,7 +235,7 @@ (enqueuer.isFieldLive(f) || enqueuer.isFieldReferenced(f) || f.getOptimizationInfo().valueHasBeenPropagated()) - && appView.graphLens().getOriginalFieldSignature(f.field).holder + && appView.graphLens().getOriginalFieldSignature(f.getReference()).holder == sourceClass.type)); Iterables.addAll( filteredMembers, @@ -244,7 +244,7 @@ (enqueuer.isMethodLive(m) || enqueuer.isMethodTargeted(m) || m.getOptimizationInfo().returnValueHasBeenPropagated()) - && appView.graphLens().getOriginalMethodSignature(m.method).holder + && appView.graphLens().getOriginalMethodSignature(m.getReference()).holder == sourceClass.type)); // If the number of member rules to hold is more than live members, we can't make it.
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 81239aa..7e9b166 100644 --- a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java +++ b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
@@ -307,13 +307,13 @@ @Override public KeepMethodInfo getMethodInfo(DexEncodedMethod method, DexProgramClass holder) { assert method.getHolderType() == holder.type; - return keepMethodInfo.getOrDefault(method.method, KeepMethodInfo.bottom()); + return keepMethodInfo.getOrDefault(method.getReference(), KeepMethodInfo.bottom()); } @Override public KeepFieldInfo getFieldInfo(DexEncodedField field, DexProgramClass holder) { assert field.getHolderType() == holder.type; - return keepFieldInfo.getOrDefault(field.field, KeepFieldInfo.bottom()); + return keepFieldInfo.getOrDefault(field.getReference(), KeepFieldInfo.bottom()); } public void joinClass(DexProgramClass clazz, Consumer<KeepClassInfo.Joiner> fn) {
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepReason.java b/src/main/java/com/android/tools/r8/shaking/KeepReason.java index 53b944f..5e6b3fd 100644 --- a/src/main/java/com/android/tools/r8/shaking/KeepReason.java +++ b/src/main/java/com/android/tools/r8/shaking/KeepReason.java
@@ -96,12 +96,12 @@ abstract String getKind(); public DexMethod getMethod() { - return method.method; + return method.getReference(); } @Override public GraphNode getSourceNode(GraphReporter graphReporter) { - return graphReporter.getMethodGraphNode(method.method); + return graphReporter.getMethodGraphNode(method.getReference()); } } @@ -264,10 +264,10 @@ if (holder.isDexClass()) { return graphReporter.getClassGraphNode(holder.asDexClass().type); } else if (holder.isDexEncodedField()) { - return graphReporter.getFieldGraphNode(holder.asDexEncodedField().field); + return graphReporter.getFieldGraphNode(holder.asDexEncodedField().getReference()); } else { assert holder.isDexEncodedMethod(); - return graphReporter.getMethodGraphNode(holder.asDexEncodedMethod().method); + return graphReporter.getMethodGraphNode(holder.asDexEncodedMethod().getReference()); } } }
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java b/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java index 7760062..ab19637 100644 --- a/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java +++ b/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
@@ -53,7 +53,7 @@ clazz.annotations(), appInfo.dexItemFactory())) { traceAnnotationsDirectDependencies(clazz.annotations()); } - clazz.forEachField(field -> consumer.accept(field.field.type)); + clazz.forEachField(field -> consumer.accept(field.getReference().type)); clazz.forEachProgramMethodMatching( definition -> { traceMethodDirectDependencies(definition.getReference(), consumer);
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java index afb39bf..525417c 100644 --- a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java +++ b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
@@ -105,7 +105,7 @@ // Browse annotation values types in search for enum. // Each annotation value is represented by a virtual method. for (DexEncodedMethod method : clazz.virtualMethods()) { - DexProto proto = method.method.proto; + DexProto proto = method.getReference().proto; if (proto.parameters.isEmpty()) { DexType valueType = proto.returnType.toBaseType(appView.dexItemFactory()); if (valueType.isClassType()) { @@ -143,7 +143,7 @@ addDirectDependency(clazz); // Add enum classes used for values as direct dependencies. for (DexEncodedMethod method : clazz.virtualMethods()) { - DexProto proto = method.method.proto; + DexProto proto = method.getReference().proto; if (proto.parameters.isEmpty()) { DexType valueType = proto.returnType.toBaseType(appView.dexItemFactory()); if (isEnum(valueType)) {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java index c6afc11..8c0d0b4 100644 --- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java +++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java
@@ -75,11 +75,13 @@ memberRuleBuilder.setRuleType(ProguardMemberType.METHOD); memberRuleBuilder.getAccessFlags().setFlags(method.accessFlags); memberRuleBuilder.setName( - IdentifierPatternWithWildcards.withoutWildcards(method.method.name.toString())); - memberRuleBuilder.setTypeMatcher(ProguardTypeMatcher.create(method.method.proto.returnType)); - List<ProguardTypeMatcher> arguments = Arrays.stream(method.method.proto.parameters.values) - .map(ProguardTypeMatcher::create) - .collect(Collectors.toList()); + IdentifierPatternWithWildcards.withoutWildcards(method.getReference().name.toString())); + memberRuleBuilder.setTypeMatcher( + ProguardTypeMatcher.create(method.getReference().proto.returnType)); + List<ProguardTypeMatcher> arguments = + Arrays.stream(method.getReference().proto.parameters.values) + .map(ProguardTypeMatcher::create) + .collect(Collectors.toList()); memberRuleBuilder.setArguments(arguments); builder.getMemberRules().add(memberRuleBuilder.build()); return builder.build();
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java index 1b80a1e..2aba15e 100644 --- a/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java +++ b/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java
@@ -185,7 +185,8 @@ AppView<?> appView, Consumer<AnnotationMatchResult> matchedAnnotationsConsumer, DexStringCache stringCache) { - DexField originalSignature = appView.graphLens().getOriginalFieldSignature(field.field); + DexField originalSignature = + appView.graphLens().getOriginalFieldSignature(field.getReference()); switch (getRuleType()) { case ALL: case ALL_FIELDS: @@ -236,7 +237,8 @@ AppView<?> appView, Consumer<AnnotationMatchResult> matchedAnnotationsConsumer, DexStringCache stringCache) { - DexMethod originalSignature = appView.graphLens().getOriginalMethodSignature(method.method); + DexMethod originalSignature = + appView.graphLens().getOriginalMethodSignature(method.getReference()); switch (getRuleType()) { case ALL_METHODS: if (method.isClassInitializer()) { @@ -415,7 +417,7 @@ case INIT: { result.append(getName()); result.append('('); - result.append(StringUtils.join(getArguments(), ",")); + result.append(StringUtils.join(",", getArguments())); result.append(')'); break; }
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 8848ece..e78f53b 100644 --- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java +++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -387,8 +387,8 @@ assert !encodedMethod.shouldNotHaveCode(); continue; } - propagateAssumeRules(clazz.type, encodedMethod.method, subTypes, noSideEffects); - propagateAssumeRules(clazz.type, encodedMethod.method, subTypes, assumedValues); + propagateAssumeRules(clazz.type, encodedMethod.getReference(), subTypes, noSideEffects); + propagateAssumeRules(clazz.type, encodedMethod.getReference(), subTypes, assumedValues); } } @@ -414,7 +414,7 @@ if (target == null || target.getHolderType() == type) { continue; } - ProguardMemberRule ruleInSubType = assumeRulePool.get(target.method); + ProguardMemberRule ruleInSubType = assumeRulePool.get(target.getReference()); // We are looking for the greatest lower bound of assume rules from all sub types. // If any subtype doesn't have a matching assume rule, the lower bound is literally nothing. if (ruleInSubType == null) { @@ -578,7 +578,7 @@ } for (DexEncodedMethod method : clazz.virtualMethods()) { // Check if we already added this. - Wrapper<DexMethod> wrapped = MethodSignatureEquivalence.get().wrap(method.method); + Wrapper<DexMethod> wrapped = MethodSignatureEquivalence.get().wrap(method.getReference()); if (!seenMethods.add(wrapped)) { continue; } @@ -592,7 +592,10 @@ private void tryAndKeepMethodOnClass(DexEncodedMethod method, ProguardMemberRule rule) { SingleResolutionResult resolutionResult = - appView.appInfo().resolveMethodOn(originalClazz, method.method).asSingleResolution(); + appView + .appInfo() + .resolveMethodOn(originalClazz, method.getReference()) + .asSingleResolution(); if (resolutionResult == null || !resolutionResult.isVirtualTarget()) { return; } @@ -1008,7 +1011,7 @@ DexDefinition precondition, ProguardIfRule ifRule) { if (methodsMarked != null - && methodsMarked.contains(MethodSignatureEquivalence.get().wrap(method.method))) { + && methodsMarked.contains(MethodSignatureEquivalence.get().wrap(method.getReference()))) { // Ignore, method is overridden in sub class. return; } @@ -1019,7 +1022,7 @@ getClass(), "Marking method `%s` due to `%s { %s }`.", method, context, rule); } if (methodsMarked != null) { - methodsMarked.add(MethodSignatureEquivalence.get().wrap(method.method)); + methodsMarked.add(MethodSignatureEquivalence.get().wrap(method.getReference())); } addItemToSets(method, context, rule, precondition, ifRule); } @@ -1075,13 +1078,13 @@ private void includeDescriptorClasses(DexDefinition item, ProguardKeepRuleBase context) { if (item.isDexEncodedMethod()) { - DexMethod method = item.asDexEncodedMethod().method; + DexMethod method = item.asDexEncodedMethod().getReference(); includeDescriptor(item, method.proto.returnType, context); for (DexType value : method.proto.parameters.values) { includeDescriptor(item, value, context); } } else if (item.isDexEncodedField()) { - DexField field = item.asDexEncodedField().field; + DexField field = item.asDexEncodedField().getReference(); includeDescriptor(item, field.type, context); } else { assert item.isDexClass(); @@ -1114,7 +1117,7 @@ return; } if (options.isGeneratingDex() - && encodedMethod.method.isLambdaDeserializeMethod(appView.dexItemFactory())) { + && encodedMethod.getReference().isLambdaDeserializeMethod(appView.dexItemFactory())) { // Don't keep lambda deserialization methods. return; } @@ -1131,7 +1134,7 @@ "The rule `" + rule + "` is ignored because the targeting interface method `" - + encodedMethod.method.toSourceString() + + encodedMethod.getReference().toSourceString() + "` will be desugared.")); } return; @@ -1244,7 +1247,7 @@ if (!item.isDexEncodedMethod()) { throw new Unreachable(); } - whyAreYouNotInlining.add(item.asDexEncodedMethod().method); + whyAreYouNotInlining.add(item.asDexEncodedMethod().getReference()); context.markAsUsed(); } else if (context.isClassInlineRule()) { ClassInlineRule classInlineRule = context.asClassInlineRule(); @@ -1285,13 +1288,13 @@ if (item.isDexEncodedField()) { DexEncodedField field = item.asDexEncodedField(); if (field.isProgramField(appView)) { - neverPropagateValue.add(item.asDexEncodedField().field); + neverPropagateValue.add(item.asDexEncodedField().getReference()); context.markAsUsed(); } } else if (item.isDexEncodedMethod()) { DexEncodedMethod method = item.asDexEncodedMethod(); if (method.isProgramMethod(appView)) { - neverPropagateValue.add(item.asDexEncodedMethod().method); + neverPropagateValue.add(item.asDexEncodedMethod().getReference()); context.markAsUsed(); } } @@ -1301,15 +1304,15 @@ } } else if (context instanceof ProguardIdentifierNameStringRule) { if (item.isDexEncodedField()) { - identifierNameStrings.add(item.asDexEncodedField().field); + identifierNameStrings.add(item.asDexEncodedField().getReference()); context.markAsUsed(); } else if (item.isDexEncodedMethod()) { - identifierNameStrings.add(item.asDexEncodedMethod().method); + identifierNameStrings.add(item.asDexEncodedMethod().getReference()); context.markAsUsed(); } } else if (context instanceof ConstantArgumentRule) { if (item.isDexEncodedMethod()) { - keepParametersWithConstantValue.add(item.asDexEncodedMethod().method); + keepParametersWithConstantValue.add(item.asDexEncodedMethod().getReference()); context.markAsUsed(); } } else if (context instanceof ReprocessClassInitializerRule) { @@ -1317,10 +1320,10 @@ if (clazz != null && clazz.hasClassInitializer()) { switch (context.asReprocessClassInitializerRule().getType()) { case ALWAYS: - reprocess.add(clazz.getClassInitializer().method); + reprocess.add(clazz.getClassInitializer().getReference()); break; case NEVER: - neverReprocess.add(clazz.getClassInitializer().method); + neverReprocess.add(clazz.getClassInitializer().getReference()); break; default: throw new Unreachable(); @@ -1332,10 +1335,10 @@ DexEncodedMethod method = item.asDexEncodedMethod(); switch (context.asReprocessMethodRule().getType()) { case ALWAYS: - reprocess.add(method.method); + reprocess.add(method.getReference()); break; case NEVER: - neverReprocess.add(method.method); + neverReprocess.add(method.getReference()); break; default: throw new Unreachable(); @@ -1344,7 +1347,7 @@ } } else if (context instanceof UnusedArgumentRule) { if (item.isDexEncodedMethod()) { - keepUnusedArguments.add(item.asDexEncodedMethod().method); + keepUnusedArguments.add(item.asDexEncodedMethod().getReference()); context.markAsUsed(); } } else {
diff --git a/src/main/java/com/android/tools/r8/shaking/ScopedDexMethodSet.java b/src/main/java/com/android/tools/r8/shaking/ScopedDexMethodSet.java index d3b7e21..07ad580 100644 --- a/src/main/java/com/android/tools/r8/shaking/ScopedDexMethodSet.java +++ b/src/main/java/com/android/tools/r8/shaking/ScopedDexMethodSet.java
@@ -46,7 +46,7 @@ } public boolean addMethod(DexEncodedMethod method) { - Wrapper<DexMethod> wrapped = METHOD_EQUIVALENCE.wrap(method.method); + Wrapper<DexMethod> wrapped = METHOD_EQUIVALENCE.wrap(method.getReference()); if (contains(wrapped)) { return false; } @@ -55,7 +55,7 @@ } public AddMethodIfMoreVisibleResult addMethodIfMoreVisible(DexEncodedMethod method) { - Wrapper<DexMethod> wrapped = METHOD_EQUIVALENCE.wrap(method.method); + Wrapper<DexMethod> wrapped = METHOD_EQUIVALENCE.wrap(method.getReference()); DexEncodedMethod existing = lookup(wrapped); if (existing == null) { items.put(wrapped, method);
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java index 9b7a66b..6974a61 100644 --- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java +++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -276,7 +276,7 @@ AppInfoWithLiveness appInfo = appView.appInfo(); InternalOptions options = appView.options(); int firstUnreachable = - firstUnreachableIndex(methods, method -> appInfo.isLiveMethod(method.method)); + firstUnreachableIndex(methods, method -> appInfo.isLiveMethod(method.getReference())); // Return the original array if all methods are used. if (firstUnreachable == -1) { return null; @@ -295,7 +295,7 @@ method.shouldNotHaveCode() && !method.hasCode() ? method : method.toMethodThatLogsError(appView)); - methodsToKeepForConfigurationDebugging.add(method.method); + methodsToKeepForConfigurationDebugging.add(method.getReference()); } else if (appInfo.isTargetedMethod(method.getReference())) { // If the method is already abstract, and doesn't have code, let it be. if (method.shouldNotHaveCode() && !method.hasCode()) { @@ -303,7 +303,7 @@ continue; } if (Log.ENABLED) { - Log.debug(getClass(), "Making method %s abstract.", method.method); + Log.debug(getClass(), "Making method %s abstract.", method.getReference()); } // Final classes cannot be abstract, so we have to keep the method in that case. // Also some other kinds of methods cannot be abstract, so keep them around. @@ -315,7 +315,7 @@ && !method.isSynchronized() && !method.accessFlags.isPrivate() && !method.isStatic() - && !appInfo.isFailedResolutionTarget(method.method); + && !appInfo.isFailedResolutionTarget(method.getReference()); // Private methods and static methods can only be targeted yet non-live as the result of // an invalid invoke. They will not actually be called at runtime but we have to keep them // as non-abstract (see above) to produce the same failure mode. @@ -323,7 +323,7 @@ allowAbstract ? method.toAbstractMethod() : method.toEmptyThrowingMethod(options)); } else { if (Log.ENABLED) { - Log.debug(getClass(), "Removing method %s.", method.method); + Log.debug(getClass(), "Removing method %s.", method.getReference()); } unusedItemsPrinter.registerUnusedMethod(method); } @@ -356,7 +356,7 @@ reachableOrReferencedFields.add(field); } else { if (Log.ENABLED) { - Log.debug(getClass(), "Removing field %s.", field.field); + Log.debug(getClass(), "Removing field %s.", field.getReference()); } unusedItemsPrinter.registerUnusedField(field); } @@ -379,7 +379,7 @@ // Pinned field which type is never instantiated are always null, they are marked as dead // so their reads and writes are cleared, but they are still in the program. assert !field.getOptimizationInfo().isDead() || appView.appInfo().isPinned(field) - : "Expected field `" + field.field.toSourceString() + "` to be absent"; + : "Expected field `" + field.getReference().toSourceString() + "` to be absent"; } return true; }
diff --git a/src/main/java/com/android/tools/r8/shaking/UnusedItemsPrinter.java b/src/main/java/com/android/tools/r8/shaking/UnusedItemsPrinter.java index 5b89abf..6bd61cd 100644 --- a/src/main/java/com/android/tools/r8/shaking/UnusedItemsPrinter.java +++ b/src/main/java/com/android/tools/r8/shaking/UnusedItemsPrinter.java
@@ -105,15 +105,15 @@ append(accessFlags); append(" "); } - append(method.method.proto.returnType.toSourceString()); + append(method.getReference().proto.returnType.toSourceString()); append(" "); - append(method.method.name.toSourceString()); + append(method.getReference().name.toSourceString()); append("("); - for (int i = 0; i < method.method.proto.parameters.values.length; i++) { + for (int i = 0; i < method.getReference().proto.parameters.values.length; i++) { if (i != 0) { append(","); } - append(method.method.proto.parameters.values[i].toSourceString()); + append(method.getReference().proto.parameters.values[i].toSourceString()); } append(")"); newline(); @@ -126,9 +126,9 @@ append(accessFlags); append(" "); } - append(field.field.type.toSourceString()); + append(field.getReference().type.toSourceString()); append(" "); - append(field.field.name.toSourceString()); + append(field.getReference().name.toSourceString()); newline(); }
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 761b314..3475116 100644 --- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java +++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -208,7 +208,7 @@ // Map from source class to target class. private final MutableBidirectionalManyToOneMap<DexType, DexType> mergedClasses = - new BidirectionalManyToOneHashMap<>(); + BidirectionalManyToOneHashMap.newIdentityHashMap(); // Set of types that must not be merged into their subtype. private final Set<DexType> pinnedTypes = Sets.newIdentityHashSet(); @@ -512,7 +512,7 @@ } // Check if the target is overriding and narrowing the access. if (method.isPublic()) { - DexEncodedMethod targetOverride = target.lookupVirtualMethod(method.method); + DexEncodedMethod targetOverride = target.lookupVirtualMethod(method.getReference()); if (targetOverride != null && !targetOverride.isPublic()) { return true; } @@ -565,7 +565,7 @@ Set<Wrapper<DexMethod>> filteredSignatures = new HashSet<>(); for (DexProgramClass clazz : appInfo.classes()) { for (DexEncodedMethod encodedMethod : clazz.methods()) { - DexMethod method = encodedMethod.method; + DexMethod method = encodedMethod.getReference(); DexClass definition = appInfo.definitionFor(method.holder); if (definition != null && definition.isProgramClass() @@ -695,7 +695,7 @@ for (DexProgramClass clazz : appInfo.classes()) { for (DexEncodedMethod encodedMethod : clazz.methods()) { - DexMethod method = encodedMethod.method; + DexMethod method = encodedMethod.getReference(); DexMethod originalMethod = graphLens.getOriginalMethodSignature(method); DexMethod renamedMethod = graphLens.getRenamedMethodSignature(originalMethod); @@ -727,7 +727,8 @@ private boolean methodResolutionMayChange(DexProgramClass source, DexProgramClass target) { for (DexEncodedMethod virtualSourceMethod : source.virtualMethods()) { - DexEncodedMethod directTargetMethod = target.lookupDirectMethod(virtualSourceMethod.method); + DexEncodedMethod directTargetMethod = + target.lookupDirectMethod(virtualSourceMethod.getReference()); if (directTargetMethod != null) { // A private method shadows a virtual method. This situation is rare, since it is not // allowed by javac. Therefore, we just give up in this case. (In principle, it would be @@ -763,7 +764,7 @@ // Conservatively find all possible targets for this method. LookupResultSuccess lookupResult = appInfo - .resolveMethodOnInterface(method.getHolderType(), method.method) + .resolveMethodOnInterface(method.getHolderType(), method.getReference()) .lookupVirtualDispatchTargets(target, appInfo) .asLookupResultSuccess(); assert lookupResult != null; @@ -873,11 +874,12 @@ for (DexType interfaceType : target.interfaces.values) { DexClass clazz = appInfo.definitionFor(interfaceType); for (DexEncodedField staticField : clazz.staticFields()) { - staticFieldsInInterfacesOfTarget.add(equivalence.wrap(staticField.field)); + staticFieldsInInterfacesOfTarget.add(equivalence.wrap(staticField.getReference())); } } for (DexEncodedField instanceField : source.instanceFields()) { - if (staticFieldsInInterfacesOfTarget.contains(equivalence.wrap(instanceField.field))) { + if (staticFieldsInInterfacesOfTarget.contains( + equivalence.wrap(instanceField.getReference()))) { // An instruction "iget Target.f" or "iput Target.f" that used to hit a static field in an // interface would now hit an instance field from [source], so that an IncompatibleClass- // ChangeError would no longer be thrown. Abort merge. @@ -926,7 +928,7 @@ DexEncodedMethod resultingConstructor = renameConstructor(directMethod, availableMethodSignatures); add(directMethods, resultingConstructor, MethodSignatureEquivalence.get()); - blockRedirectionOfSuperCalls(resultingConstructor.method); + blockRedirectionOfSuperCalls(resultingConstructor.getReference()); } else { DexEncodedMethod resultingDirectMethod = renameMethod( @@ -934,9 +936,10 @@ availableMethodSignatures, directMethod.isClassInitializer() ? Rename.NEVER : Rename.IF_NEEDED); add(directMethods, resultingDirectMethod, MethodSignatureEquivalence.get()); - deferredRenamings.map(directMethod.method, resultingDirectMethod.method); - deferredRenamings.recordMove(directMethod.method, resultingDirectMethod.method); - blockRedirectionOfSuperCalls(resultingDirectMethod.method); + deferredRenamings.map(directMethod.getReference(), resultingDirectMethod.getReference()); + deferredRenamings.recordMove( + directMethod.getReference(), resultingDirectMethod.getReference()); + blockRedirectionOfSuperCalls(resultingDirectMethod.getReference()); } } @@ -945,7 +948,7 @@ if (shadowedBy != null) { if (virtualMethod.isAbstract()) { // Remove abstract/interface methods that are shadowed. - deferredRenamings.map(virtualMethod.method, shadowedBy.method); + deferredRenamings.map(virtualMethod.getReference(), shadowedBy.getReference()); // The override now corresponds to the method in the parent, so unset its synthetic flag // if the method in the parent is not synthetic. @@ -977,8 +980,10 @@ renameMethod(virtualMethod, availableMethodSignatures, Rename.NEVER); resultingVirtualMethod.setLibraryMethodOverride( virtualMethod.isLibraryMethodOverride()); - deferredRenamings.map(virtualMethod.method, resultingVirtualMethod.method); - deferredRenamings.recordMove(virtualMethod.method, resultingVirtualMethod.method); + deferredRenamings.map( + virtualMethod.getReference(), resultingVirtualMethod.getReference()); + deferredRenamings.recordMove( + virtualMethod.getReference(), resultingVirtualMethod.getReference()); add(virtualMethods, resultingVirtualMethod, MethodSignatureEquivalence.get()); continue; } @@ -1005,7 +1010,7 @@ makeStatic(resultingDirectMethod); // Update method pool collection now that we are adding a new public method. - methodPoolForTarget.seen(resultingDirectMethod.method); + methodPoolForTarget.seen(resultingDirectMethod.getReference()); } else { // This virtual method could be called directly from a sub class via an invoke-super in- // struction. Therefore, we translate this virtual method into a direct method, such that @@ -1019,8 +1024,9 @@ // Record that invoke-super instructions in the target class should be redirected to the // newly created direct method. - redirectSuperCallsInTarget(virtualMethod.method, resultingDirectMethod.method); - blockRedirectionOfSuperCalls(resultingDirectMethod.method); + redirectSuperCallsInTarget( + virtualMethod.getReference(), resultingDirectMethod.getReference()); + blockRedirectionOfSuperCalls(resultingDirectMethod.getReference()); if (shadowedBy == null) { // In addition to the newly added direct method, create a virtual method such that we do @@ -1029,12 +1035,14 @@ // it turns out that the method is never used, it will be removed by the final round // of tree shaking. shadowedBy = buildBridgeMethod(virtualMethod, resultingDirectMethod); - deferredRenamings.recordCreationOfBridgeMethod(virtualMethod.method, shadowedBy.method); + deferredRenamings.recordCreationOfBridgeMethod( + virtualMethod.getReference(), shadowedBy.getReference()); add(virtualMethods, shadowedBy, MethodSignatureEquivalence.get()); } - deferredRenamings.map(virtualMethod.method, shadowedBy.method); - deferredRenamings.recordMove(virtualMethod.method, resultingDirectMethod.method); + deferredRenamings.map(virtualMethod.getReference(), shadowedBy.getReference()); + deferredRenamings.recordMove( + virtualMethod.getReference(), resultingDirectMethod.getReference()); } if (abortMerge) { @@ -1046,7 +1054,7 @@ // Step 2: Merge fields Set<DexString> existingFieldNames = new HashSet<>(); for (DexEncodedField field : target.fields()) { - existingFieldNames.add(field.field.name); + existingFieldNames.add(field.getReference().name); } // In principle, we could allow multiple fields with the same name, and then only rename the @@ -1223,8 +1231,8 @@ private DexEncodedMethod buildBridgeMethod( DexEncodedMethod method, DexEncodedMethod invocationTarget) { DexType holder = target.type; - DexProto proto = method.method.proto; - DexString name = method.method.name; + DexProto proto = method.getReference().proto; + DexString name = method.getReference().name; DexMethod newMethod = application.dexItemFactory.createMethod(holder, proto, name); MethodAccessFlags accessFlags = method.accessFlags.copy(); accessFlags.setBridge(); @@ -1235,8 +1243,8 @@ SynthesizedBridgeCode code = new SynthesizedBridgeCode( newMethod, - appView.graphLens().getOriginalMethodSignature(method.method), - invocationTarget.method, + appView.graphLens().getOriginalMethodSignature(method.getReference()), + invocationTarget.getReference(), invocationTarget.isPrivateMethod() ? DIRECT : STATIC, target.isInterface()); @@ -1265,7 +1273,7 @@ // Returns the method that shadows the given method, or null if method is not shadowed. private DexEncodedMethod findMethodInTarget(DexEncodedMethod method) { - ResolutionResult resolutionResult = appInfo.resolveMethodOn(target, method.method); + ResolutionResult resolutionResult = appInfo.resolveMethodOn(target, method.getReference()); if (!resolutionResult.isSingleResolution()) { // May happen in case of missing classes, or if multiple implementations were found. abortMerge = true; @@ -1285,7 +1293,7 @@ "The non-abstract type `" + target.type.toSourceString() + "` does not implement the method `" - + method.method.toSourceString() + + method.getReference().toSourceString() + "`."); } } @@ -1321,8 +1329,8 @@ int i = 0; for (DexEncodedField field : sourceFields) { DexEncodedField resultingField = renameFieldIfNeeded(field, availableFieldSignatures); - existingFieldNames.add(resultingField.field.name); - deferredRenamings.map(field.field, resultingField.field); + existingFieldNames.add(resultingField.getReference().name); + deferredRenamings.map(field.getReference(), resultingField.getReference()); result[i] = resultingField; i++; } @@ -1354,14 +1362,15 @@ do { DexString newName = getFreshName(TEMPORARY_INSTANCE_INITIALIZER_PREFIX, count, oldHolder); newSignature = - application.dexItemFactory.createMethod(target.type, method.method.proto, newName); + application.dexItemFactory.createMethod( + target.type, method.getReference().proto, newName); count++; } while (!availableMethodSignatures.test(newSignature)); DexEncodedMethod result = method.toTypeSubstitutedMethod(newSignature); result.getMutableOptimizationInfo().markForceInline(); - deferredRenamings.map(method.method, result.method); - deferredRenamings.recordMove(method.method, result.method); + deferredRenamings.map(method.getReference(), result.getReference()); + deferredRenamings.recordMove(method.getReference(), result.getReference()); // Renamed constructors turn into ordinary private functions. They can be private, as // they are only references from their direct subclass, which they were merged into. result.accessFlags.unsetConstructor(); @@ -1371,7 +1380,7 @@ private DexEncodedMethod renameMethod( DexEncodedMethod method, Predicate<DexMethod> availableMethodSignatures, Rename strategy) { - return renameMethod(method, availableMethodSignatures, strategy, method.method.proto); + return renameMethod(method, availableMethodSignatures, strategy, method.getReference().proto); } private DexEncodedMethod renameMethod( @@ -1382,7 +1391,7 @@ // We cannot handle renaming static initializers yet and constructors should have been // renamed already. assert !method.accessFlags.isConstructor() || strategy == Rename.NEVER; - DexString oldName = method.method.name; + DexString oldName = method.getReference().name; DexType oldHolder = method.getHolderType(); DexMethod newSignature; @@ -1417,17 +1426,18 @@ private DexEncodedField renameFieldIfNeeded( DexEncodedField field, Predicate<DexField> availableFieldSignatures) { - DexString oldName = field.field.name; + DexString oldName = field.getReference().name; DexType oldHolder = field.getHolderType(); DexField newSignature = - application.dexItemFactory.createField(target.type, field.field.type, oldName); + application.dexItemFactory.createField(target.type, field.getReference().type, oldName); if (!availableFieldSignatures.test(newSignature)) { int count = 1; do { DexString newName = getFreshName(oldName.toSourceString(), count, oldHolder); newSignature = - application.dexItemFactory.createField(target.type, field.field.type, newName); + application.dexItemFactory.createField( + target.type, field.getReference().type, newName); count++; } while (!availableFieldSignatures.test(newSignature)); } @@ -1520,7 +1530,7 @@ @Override public DexEncodedMethod recordMethodChange( DexEncodedMethod method, DexEncodedMethod newMethod) { - recordMethodChange(method.method, newMethod.method); + recordMethodChange(method.getReference(), newMethod.getReference()); if (newMethod.isNonPrivateVirtualMethod()) { // Since we changed the return type or one of the parameters, this method cannot be a // classpath or library method override, since we only class merge program classes.
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java index 008380c..467c168 100644 --- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java +++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
@@ -11,8 +11,7 @@ import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexType; -import com.android.tools.r8.graph.GraphLens; -import com.android.tools.r8.graph.GraphLens.NestedGraphLens; +import com.android.tools.r8.graph.NestedGraphLens; import com.android.tools.r8.graph.RewrittenPrototypeDescription; import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses; import com.android.tools.r8.ir.code.Invoke.Type; @@ -75,16 +74,9 @@ Set<DexMethod> mergedMethods, Map<DexType, Map<DexMethod, GraphLensLookupResultProvider>> contextualVirtualToDirectMethodMaps, - BidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures, - Map<DexMethod, DexMethod> originalMethodSignaturesForBridges, - GraphLens previousLens) { - super( - mergedClasses.getForwardMap(), - methodMap, - fieldMap, - originalMethodSignatures, - previousLens, - appView.dexItemFactory()); + BidirectionalOneToOneMap<DexMethod, DexMethod> newMethodSignatures, + Map<DexMethod, DexMethod> originalMethodSignaturesForBridges) { + super(appView, fieldMap, methodMap, mergedClasses.getForwardMap(), newMethodSignatures); this.appView = appView; this.mergedClasses = mergedClasses; this.contextualVirtualToDirectMethodMaps = contextualVirtualToDirectMethodMaps; @@ -172,7 +164,7 @@ private final Map<DexType, Map<DexMethod, GraphLensLookupResultProvider>> contextualVirtualToDirectMethodMaps = new IdentityHashMap<>(); - private final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures = + private final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> newMethodSignatures = new BidirectionalOneToOneHashMap<>(); private final Map<DexMethod, DexMethod> originalMethodSignaturesForBridges = new IdentityHashMap<>(); @@ -216,8 +208,8 @@ context); } } - builder.originalMethodSignatures.forEach( - (renamedMethodSignature, originalMethodSignature) -> + builder.newMethodSignatures.forEach( + (originalMethodSignature, renamedMethodSignature) -> newBuilder.recordMove( originalMethodSignature, builder.getMethodSignatureAfterClassMerging( @@ -244,9 +236,8 @@ methodMap, mergedMethodsBuilder.build(), contextualVirtualToDirectMethodMaps, - originalMethodSignatures, - originalMethodSignaturesForBridges, - appView.graphLens()); + newMethodSignatures, + originalMethodSignaturesForBridges); } private DexField getFieldSignatureAfterClassMerging( @@ -309,7 +300,7 @@ } public boolean hasOriginalSignatureMappingFor(DexMethod method) { - return originalMethodSignatures.containsKey(method) + return newMethodSignatures.containsValue(method) || originalMethodSignaturesForBridges.containsKey(method); } @@ -327,7 +318,7 @@ } public void recordMove(DexMethod from, DexMethod to) { - originalMethodSignatures.put(to, from); + newMethodSignatures.put(from, to); } public void recordCreationOfBridgeMethod(DexMethod from, DexMethod to) { @@ -345,7 +336,7 @@ fieldMap.putAll(builder.fieldMap); methodMap.putAll(builder.methodMap); mergedMethodsBuilder.addAll(builder.mergedMethodsBuilder.build()); - originalMethodSignatures.putAll(builder.originalMethodSignatures); + newMethodSignatures.putAll(builder.newMethodSignatures); originalMethodSignaturesForBridges.putAll(builder.originalMethodSignaturesForBridges); for (DexType context : builder.contextualVirtualToDirectMethodMaps.keySet()) { Map<DexMethod, GraphLensLookupResultProvider> current =
diff --git a/src/main/java/com/android/tools/r8/shaking/WhyAreYouKeepingConsumer.java b/src/main/java/com/android/tools/r8/shaking/WhyAreYouKeepingConsumer.java index d56e455..1099f62 100644 --- a/src/main/java/com/android/tools/r8/shaking/WhyAreYouKeepingConsumer.java +++ b/src/main/java/com/android/tools/r8/shaking/WhyAreYouKeepingConsumer.java
@@ -211,8 +211,8 @@ + '.' + method.getMethodName() + StringUtils.join( - ListUtils.map(method.getFormalTypes(), TypeReference::getTypeName), ",", + ListUtils.map(method.getFormalTypes(), TypeReference::getTypeName), BraceType.PARENS); } if (node instanceof FieldGraphNode) {
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java index d610175..ed9d843 100644 --- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java +++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -18,8 +18,8 @@ import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GraphLens; -import com.android.tools.r8.graph.GraphLens.NestedGraphLens; import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens; +import com.android.tools.r8.graph.NestedGraphLens; import com.android.tools.r8.graph.PrunedItems; import com.android.tools.r8.graph.TreeFixerBase; import com.android.tools.r8.ir.code.NumberGenerator; @@ -28,11 +28,9 @@ import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.SetUtils; -import com.android.tools.r8.utils.collections.BidirectionalManyToManyRepresentativeMap; import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap; import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap; -import com.android.tools.r8.utils.collections.BidirectionalOneToManyRepresentativeHashMap; -import com.android.tools.r8.utils.collections.MutableBidirectionalOneToManyRepresentativeMap; +import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneRepresentativeMap; import com.android.tools.r8.utils.structural.RepresentativeMap; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; @@ -72,13 +70,11 @@ public static class SyntheticFinalizationGraphLens extends NestedGraphLens { private SyntheticFinalizationGraphLens( - GraphLens previous, - Map<DexType, DexType> typeMap, + AppView<?> appView, BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap, - Map<DexMethod, DexMethod> methodMap, - BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> originalMethodSignatures, - DexItemFactory factory) { - super(typeMap, methodMap, fieldMap, originalMethodSignatures, previous, factory); + BidirectionalManyToOneRepresentativeMap<DexMethod, DexMethod> methodMap, + Map<DexType, DexType> typeMap) { + super(appView, fieldMap, methodMap, typeMap); } @Override @@ -89,13 +85,11 @@ private static class Builder { - Map<DexType, DexType> typeMap = new IdentityHashMap<>(); - BidirectionalManyToOneRepresentativeHashMap<DexField, DexField> fieldMap = - new BidirectionalManyToOneRepresentativeHashMap<>(); - Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>(); - - protected final MutableBidirectionalOneToManyRepresentativeMap<DexMethod, DexMethod> - originalMethodSignatures = new BidirectionalOneToManyRepresentativeHashMap<>(); + private final BidirectionalManyToOneRepresentativeHashMap<DexField, DexField> fieldMap = + BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap(); + private final MutableBidirectionalManyToOneRepresentativeMap<DexMethod, DexMethod> methodMap = + BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap(); + private final Map<DexType, DexType> typeMap = new IdentityHashMap<>(); void move(DexType from, DexType to) { DexType old = typeMap.put(from, to); @@ -108,22 +102,14 @@ } void move(DexMethod from, DexMethod to) { - DexMethod old = methodMap.put(from, to); - assert old == null || old == to; - originalMethodSignatures.put(to, from); + methodMap.put(from, to); } - SyntheticFinalizationGraphLens build(GraphLens previous, DexItemFactory factory) { + SyntheticFinalizationGraphLens build(AppView<?> appView) { if (typeMap.isEmpty() && fieldMap.isEmpty() && methodMap.isEmpty()) { return null; } - return new SyntheticFinalizationGraphLens( - previous, - typeMap, - fieldMap, - methodMap, - originalMethodSignatures, - factory); + return new SyntheticFinalizationGraphLens(appView, fieldMap, methodMap, typeMap); } } @@ -262,7 +248,7 @@ new CommittedSyntheticsCollection( committed.getLegacyTypes(), finalMethods, finalClasses), ImmutableList.of()), - lensBuilder.build(appView.graphLens(), appView.dexItemFactory()), + lensBuilder.build(appView), PrunedItems.builder().setPrunedApp(application).addRemovedClasses(prunedSynthetics).build(), mainDexInfoBuilder.build()); }
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java index 7148738..cb1e91b 100644 --- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java +++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -31,6 +31,7 @@ HORIZONTAL_INIT_TYPE_ARGUMENT_2(SYNTHETIC_CLASS_SEPARATOR + "IA$2", false, true), HORIZONTAL_INIT_TYPE_ARGUMENT_3(SYNTHETIC_CLASS_SEPARATOR + "IA$3", false, true), // Method synthetics. + RECORD_HELPER("Record", true), BACKPORT("Backport", true), STATIC_INTERFACE_CALL("StaticInterfaceCall", true), TO_STRING_IF_NOT_NULL("ToStringIfNotNull", true),
diff --git a/src/main/java/com/android/tools/r8/tracereferences/KeepRuleFormatter.java b/src/main/java/com/android/tools/r8/tracereferences/KeepRuleFormatter.java index c28ef5d..b768c52 100644 --- a/src/main/java/com/android/tools/r8/tracereferences/KeepRuleFormatter.java +++ b/src/main/java/com/android/tools/r8/tracereferences/KeepRuleFormatter.java
@@ -73,7 +73,7 @@ @Override protected void printPackageNames(List<String> packageNames) { if (!packageNames.isEmpty()) { - append("-keeppackagenames " + StringUtils.join(packageNames, ",") + System.lineSeparator()); + append("-keeppackagenames " + StringUtils.join(",", packageNames) + System.lineSeparator()); } }
diff --git a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java index 039f28d..16a6bfc 100644 --- a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java +++ b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
@@ -301,7 +301,7 @@ addType(field.type); DexEncodedField baseField = appInfo.resolveField(field).getResolvedField(); if (baseField != null && baseField.getHolderType() != field.holder) { - field = baseField.field; + field = baseField.getReference(); } addType(field.holder); TracedFieldImpl tracedField = new TracedFieldImpl(field, baseField); @@ -381,9 +381,9 @@ ResolutionResult resolutionResult = appInfo.unsafeResolveMethodDueToDexFormat(method); DexEncodedMethod target = resolutionResult.isVirtualTarget() ? resolutionResult.getSingleTarget() : null; - if (target != null && target.method != method) { + if (target != null && target.getReference() != method) { addType(method.holder); - addMethod(target.method); + addMethod(target.getReference()); } else { addMethod(method); } @@ -397,9 +397,9 @@ @Override public void registerInvokeStatic(DexMethod method) { DexEncodedMethod target = appInfo.unsafeResolveMethodDueToDexFormat(method).getSingleTarget(); - if (target != null && target.method != method) { + if (target != null && target.getReference() != method) { addType(method.holder); - addMethod(target.method); + addMethod(target.getReference()); } else { addMethod(method); } @@ -456,7 +456,7 @@ } private void registerField(DexEncodedField field) { - registerTypeReference(field.field.type); + registerTypeReference(field.getReference().type); } private void registerMethod(ProgramMethod method) { @@ -488,10 +488,11 @@ clazz.forEachMethod( method -> { ResolutionResult resolutionResult = - appInfo.resolveMethodOn(superType, method.method, superType != clazz.superType); + appInfo.resolveMethodOn( + superType, method.getReference(), superType != clazz.superType); DexEncodedMethod dexEncodedMethod = resolutionResult.getSingleTarget(); if (dexEncodedMethod != null) { - addMethod(dexEncodedMethod.method); + addMethod(dexEncodedMethod.getReference()); } }); }
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java index d1f6e4c..d58387f 100644 --- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java +++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -510,7 +510,7 @@ for (String mainDexClass : getMainDexClasses()) { mainDexList.add(mainDexClass.replace(".", "/") + CLASS_EXTENSION); } - String join = StringUtils.join(mainDexList, "\n"); + String join = StringUtils.join("\n", mainDexList); writeToZipStream(out, dumpMainDexListResourceFileName, join.getBytes(), ZipEntry.DEFLATED); } if (options.hasMainDexKeepRules()) {
diff --git a/src/main/java/com/android/tools/r8/utils/BooleanBox.java b/src/main/java/com/android/tools/r8/utils/BooleanBox.java index f6b790d..5ad9494 100644 --- a/src/main/java/com/android/tools/r8/utils/BooleanBox.java +++ b/src/main/java/com/android/tools/r8/utils/BooleanBox.java
@@ -9,6 +9,7 @@ public class BooleanBox { private boolean value; + private boolean assigned = false; public BooleanBox() {} @@ -39,10 +40,23 @@ } public void set(boolean value) { + assigned = true; this.value = value; } public void unset() { set(false); } + + public void and(boolean value) { + set(value && this.value); + } + + public void or(boolean value) { + set(value || this.value); + } + + public boolean isAssigned() { + return assigned; + } }
diff --git a/src/main/java/com/android/tools/r8/utils/ClassMap.java b/src/main/java/com/android/tools/r8/utils/ClassMap.java index c885d9e..23d71ee 100644 --- a/src/main/java/com/android/tools/r8/utils/ClassMap.java +++ b/src/main/java/com/android/tools/r8/utils/ClassMap.java
@@ -120,9 +120,7 @@ * has to be run at a join point, concurrent accesses may be confused. */ public void clearType(DexType type) { - if (classes.containsKey(type)) { - classes.remove(type); - } + classes.remove(type); ClassProvider<T> provider = classProvider.get(); if (provider == null) { return;
diff --git a/src/main/java/com/android/tools/r8/utils/ClassProvider.java b/src/main/java/com/android/tools/r8/utils/ClassProvider.java index af272b8..e46606e 100644 --- a/src/main/java/com/android/tools/r8/utils/ClassProvider.java +++ b/src/main/java/com/android/tools/r8/utils/ClassProvider.java
@@ -72,7 +72,7 @@ } public FilteringClassProvider<T> without(Set<DexType> filteredTypes) { - return new FilteringClassProvider(classKind, this, filteredTypes); + return new FilteringClassProvider<>(classKind, this, filteredTypes); } /** Create class provider for preloaded classes. */ @@ -167,7 +167,7 @@ public FilteringClassProvider<T> without(Set<DexType> filteredTypes) { ImmutableSet<DexType> newSet = ImmutableSet.<DexType>builder().addAll(filteredOut).addAll(filteredTypes).build(); - return new FilteringClassProvider(getClassKind(), provider, newSet); + return new FilteringClassProvider<>(getClassKind(), provider, newSet); } @Override
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 54bbbcc..7a99160 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -270,8 +270,6 @@ public boolean encodeChecksums = false; public BiPredicate<String, Long> dexClassChecksumFilter = (name, checksum) -> true; public boolean cfToCfDesugar = false; - // TODO(b/172496438): Temporarily enable publicizing package-private overrides. - public boolean enablePackagePrivateAwarePublicization = false; public int callGraphLikelySpuriousCallEdgeThreshold = 50; @@ -1909,4 +1907,12 @@ public boolean canHaveSwitchMaxIntBug() { return isGeneratingDex() && minApiLevel < AndroidApiLevel.K.getLevel(); } + + // On Dalvik the methods Integer.parseInt and Long.parseLong does not support strings with a '+' + // prefix + // + // See b/182137865. + public boolean canParseNumbersWithPlusPrefix() { + return minApiLevel > AndroidApiLevel.K.getLevel(); + } }
diff --git a/src/main/java/com/android/tools/r8/utils/IterableUtils.java b/src/main/java/com/android/tools/r8/utils/IterableUtils.java index ce8396f..1354a33 100644 --- a/src/main/java/com/android/tools/r8/utils/IterableUtils.java +++ b/src/main/java/com/android/tools/r8/utils/IterableUtils.java
@@ -12,6 +12,7 @@ import java.util.List; import java.util.function.BiFunction; import java.util.function.BiPredicate; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -151,4 +152,10 @@ } return !iterator.hasNext(); } + + public static <T, R> Iterable<R> fromMethod(Consumer<Consumer<T>> method, Function<T, R> mapper) { + List<R> ts = new ArrayList<>(); + method.accept(t -> ts.add(mapper.apply(t))); + return ts; + } }
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java index b1099e1..47ccd91 100644 --- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java +++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -357,11 +357,12 @@ } } - DexMethod originalMethod = appView.graphLens().getOriginalMethodSignature(method.method); + DexMethod originalMethod = + appView.graphLens().getOriginalMethodSignature(method.getReference()); MethodSignature originalSignature = MethodSignature.fromDexMethod(originalMethod, originalMethod.holder != originalType); - DexString obfuscatedNameDexString = namingLens.lookupName(method.method); + DexString obfuscatedNameDexString = namingLens.lookupName(method.getReference()); String obfuscatedName = obfuscatedNameDexString.toString(); // Add simple "a() -> b" mapping if we won't have any other with concrete line numbers @@ -467,7 +468,7 @@ } allSeenAreInstanceInitializers = false; // If the method is pinned, we cannot minify it. - if (!keepInfo.isMinificationAllowed(method.method, appView, appView.options())) { + if (!keepInfo.isMinificationAllowed(method.getReference(), appView, appView.options())) { continue; } // With desugared library, call-backs names are reserved here. @@ -477,16 +478,17 @@ // We use the same name for interface names even if it has different types. DexProgramClass clazz = appView.definitionForProgramType(method.getHolderType()); DexClassAndMethod lookupResult = - appView.appInfo().lookupMaximallySpecificMethod(clazz, method.method); + appView.appInfo().lookupMaximallySpecificMethod(clazz, method.getReference()); if (lookupResult == null) { // We cannot rename methods we cannot look up. continue; } - String errorString = method.method.qualifiedName() + " is not kept but is overloaded"; + String errorString = method.getReference().qualifiedName() + " is not kept but is overloaded"; assert lookupResult.getHolder().isInterface() : errorString; // TODO(b/159113601): Reenable assert. - assert true || originalName == null || originalName.equals(method.method.name) : errorString; - originalName = method.method.name; + assert true || originalName == null || originalName.equals(method.getReference().name) + : errorString; + originalName = method.getReference().name; } return true; } @@ -544,7 +546,7 @@ Supplier<Builder> onDemandClassNamingBuilder) { clazz.forEachField( dexEncodedField -> { - DexField dexField = dexEncodedField.field; + DexField dexField = dexEncodedField.getReference(); DexField originalField = graphLens.getOriginalFieldSignature(dexField); DexString renamedName = namingLens.lookupName(dexField); if (renamedName != originalField.name || originalField.holder != originalType) { @@ -562,7 +564,7 @@ new IdentityHashMap<>(clazz.getMethodCollection().size()); for (DexEncodedMethod encodedMethod : clazz.methods()) { // Add method only if renamed, moved, or contains positions. - DexMethod method = encodedMethod.method; + DexMethod method = encodedMethod.getReference(); DexString renamedName = namingLens.lookupName(method); if (renamedName != method.name || graphLens.getOriginalMethodSignature(method) != method @@ -626,7 +628,7 @@ PositionEventEmitter positionEventEmitter = new PositionEventEmitter( application.dexItemFactory, - appView.graphLens().getOriginalMethodSignature(method.method), + appView.graphLens().getOriginalMethodSignature(method.getReference()), processedEvents); Box<Boolean> inlinedOriginalPosition = new Box<>(false); @@ -634,7 +636,8 @@ // Debug event visitor to map line numbers. DexDebugEventVisitor visitor = new DexDebugPositionState( - debugInfo.startLine, appView.graphLens().getOriginalMethodSignature(method.method)) { + debugInfo.startLine, + appView.graphLens().getOriginalMethodSignature(method.getReference())) { // Keep track of what PC has been emitted. private int emittedPc = 0; @@ -734,7 +737,7 @@ Pair<Integer, Position> lastPosition = new Pair<>(); DexDebugEventVisitor visitor = - new DexDebugPositionState(debugInfo.startLine, method.method) { + new DexDebugPositionState(debugInfo.startLine, method.getReference()) { @Override public void visit(Default defaultEvent) { super.visit(defaultEvent);
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java index fff5425..8c3e592 100644 --- a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java +++ b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
@@ -62,10 +62,7 @@ // All other conflicts are reported as a fatal error. return (DexProgramClass a, DexProgramClass b) -> { assert a.type == b.type; - if (a.originatesFromDexResource() - && b.originatesFromDexResource() - && a.accessFlags.isSynthetic() - && b.accessFlags.isSynthetic()) { + if (a.accessFlags.isSynthetic() && b.accessFlags.isSynthetic()) { return mergeClasses(reporter, a, b); } throw reportDuplicateTypes(reporter, a, b); @@ -82,7 +79,8 @@ private static DexProgramClass mergeClasses( Reporter reporter, DexProgramClass a, DexProgramClass b) { - if (a.type.isLegacySynthesizedTypeAllowedDuplication()) { + if (a.type.isLegacySynthesizedTypeAllowedDuplication() + || a.type.isSynthesizedTypeAllowedDuplication()) { assert assertEqualClasses(a, b); return a; }
diff --git a/src/main/java/com/android/tools/r8/utils/StringUtils.java b/src/main/java/com/android/tools/r8/utils/StringUtils.java index 8f398ac..9be7a5e 100644 --- a/src/main/java/com/android/tools/r8/utils/StringUtils.java +++ b/src/main/java/com/android/tools/r8/utils/StringUtils.java
@@ -124,20 +124,20 @@ return builder; } - public static <T> String join(Collection<T> collection, String separator) { - return join(collection, separator, BraceType.NONE); + public static String join(String separator, String... strings) { + return join(separator, Arrays.asList(strings)); + } + + public static <T> String join(String separator, Iterable<T> iterable) { + return join(separator, iterable, BraceType.NONE); } public static <T> String join(String separator, Iterable<T> iterable, Function<T, String> fn) { return join(separator, iterable, fn, BraceType.NONE); } - public static String join(String separator, String... strings) { - return join(Arrays.asList(strings), separator, BraceType.NONE); - } - - public static <T> String join(Collection<T> collection, String separator, BraceType brace) { - return join(separator, collection, Object::toString, brace); + public static <T> String join(String separator, Iterable<T> iterable, BraceType brace) { + return join(separator, iterable, Object::toString, brace); } public static <T> String join( @@ -174,7 +174,7 @@ } public static <T> String joinLines(Collection<T> collection) { - return join(collection, LINE_SEPARATOR, BraceType.NONE); + return join(LINE_SEPARATOR, collection, BraceType.NONE); } public static List<String> splitLines(String content) {
diff --git a/src/main/java/com/android/tools/r8/utils/WorkList.java b/src/main/java/com/android/tools/r8/utils/WorkList.java index e5fb33f..4279cb7 100644 --- a/src/main/java/com/android/tools/r8/utils/WorkList.java +++ b/src/main/java/com/android/tools/r8/utils/WorkList.java
@@ -27,7 +27,7 @@ } public static <T> WorkList<T> newIdentityWorkList() { - return new WorkList<T>(EqualityTest.IDENTITY); + return new WorkList<>(EqualityTest.IDENTITY); } public static <T> WorkList<T> newIdentityWorkList(T item) { @@ -60,7 +60,7 @@ items.forEach(workingList::addLast); } - public void addIfNotSeen(Iterable<T> items) { + public void addIfNotSeen(Iterable<? extends T> items) { items.forEach(this::addIfNotSeen); }
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneHashMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneHashMap.java index b75d224..1e53a14 100644 --- a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneHashMap.java +++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneHashMap.java
@@ -17,11 +17,11 @@ private final Map<K, V> backing; private final Map<V, Set<K>> inverse; - public BidirectionalManyToOneHashMap() { - this(new IdentityHashMap<>(), new IdentityHashMap<>()); + public static <K, V> BidirectionalManyToOneHashMap<K, V> newIdentityHashMap() { + return new BidirectionalManyToOneHashMap<>(new IdentityHashMap<>(), new IdentityHashMap<>()); } - private BidirectionalManyToOneHashMap(Map<K, V> backing, Map<V, Set<K>> inverse) { + protected BidirectionalManyToOneHashMap(Map<K, V> backing, Map<V, Set<K>> inverse) { this.backing = backing; this.inverse = inverse; }
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeHashMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeHashMap.java index 4c2f3a8..ffd653e 100644 --- a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeHashMap.java +++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeHashMap.java
@@ -13,7 +13,18 @@ extends BidirectionalManyToOneHashMap<K, V> implements MutableBidirectionalManyToOneRepresentativeMap<K, V> { - private final Map<V, K> representatives = new IdentityHashMap<>(); + private final Map<V, K> representatives; + + public static <K, V> BidirectionalManyToOneRepresentativeHashMap<K, V> newIdentityHashMap() { + return new BidirectionalManyToOneRepresentativeHashMap<>( + new IdentityHashMap<>(), new IdentityHashMap<>(), new IdentityHashMap<>()); + } + + private BidirectionalManyToOneRepresentativeHashMap( + Map<K, V> backing, Map<V, Set<K>> inverse, Map<V, K> representatives) { + super(backing, inverse); + this.representatives = representatives; + } @Override public void clear() {
diff --git a/src/test/examplesJava9/backport/IntegerBackportJava9Main.java b/src/test/examplesJava9/backport/IntegerBackportJava9Main.java index 30e9086..8188fe1 100644 --- a/src/test/examplesJava9/backport/IntegerBackportJava9Main.java +++ b/src/test/examplesJava9/backport/IntegerBackportJava9Main.java
@@ -22,10 +22,10 @@ }; public static void main(String[] args) { - testParseIntegerSubsequenceWithRadix(args.length == 0 || !args[0].startsWith("4.")); + testParseIntegerSubsequenceWithRadix(); } - private static void testParseIntegerSubsequenceWithRadix(boolean supportsPlusPrefix) { + private static void testParseIntegerSubsequenceWithRadix() { for (int value : interestingValues) { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { for (String prefix : new String[] {"", "x", "xxx"}) { @@ -34,7 +34,7 @@ int start = prefix.length(); int end = valueString.length() - postfix.length(); assertEquals(valueString, value, Integer.parseInt(valueString, start, end, radix)); - if (value > 0 && supportsPlusPrefix) { + if (value > 0) { valueString = prefix + '+' + Long.toString(value, radix) + postfix; end++; assertEquals(valueString, value, Integer.parseInt(valueString, start, end, radix)); @@ -45,24 +45,29 @@ } try { - throw new AssertionError(Long.parseUnsignedLong("0", 0, 1, Character.MIN_RADIX - 1)); + throw new AssertionError(Integer.parseInt("0", 0, 1, Character.MIN_RADIX - 1)); } catch (IllegalArgumentException expected) { } try { - throw new AssertionError(Long.parseUnsignedLong("0", 0, 1, Character.MAX_RADIX + 1)); + throw new AssertionError(Integer.parseInt("0", 0, 1, Character.MAX_RADIX + 1)); } catch (IllegalArgumentException expected) { } try { - throw new AssertionError(Long.parseUnsignedLong("", 0, 0, 16)); + throw new AssertionError(Integer.parseInt("", 0, 0, 16)); } catch (NumberFormatException expected) { } try { - throw new AssertionError(Long.parseUnsignedLong("-", 0, 1, 16)); + throw new AssertionError(Integer.parseInt("-", 0, 1, 16)); } catch (NumberFormatException expected) { } try { - throw new AssertionError(Long.parseUnsignedLong("+", 0, 1, 16)); + throw new AssertionError(Integer.parseInt("+", 0, 1, 16)); + } catch (NumberFormatException expected) { + } + + try { + throw new AssertionError(Integer.parseInt("+a", 0, 2, 10)); } catch (NumberFormatException expected) { }
diff --git a/src/test/examplesJava9/backport/LongBackportJava9Main.java b/src/test/examplesJava9/backport/LongBackportJava9Main.java index 1634a43..f24c337 100644 --- a/src/test/examplesJava9/backport/LongBackportJava9Main.java +++ b/src/test/examplesJava9/backport/LongBackportJava9Main.java
@@ -24,11 +24,11 @@ }; public static void main(String[] args) { - testParseLongSubsequenceWithRadix(args.length == 0 || !args[0].startsWith("4.")); + testParseLongSubsequenceWithRadix(); testParseUnsignedLongSubsequenceWithRadix(); } - private static void testParseLongSubsequenceWithRadix(boolean supportsPlusPrefix) { + private static void testParseLongSubsequenceWithRadix() { for (long value : interestingValues) { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { for (String prefix : new String[] {"", "x", "xxx"}) { @@ -37,7 +37,7 @@ int start = prefix.length(); int end = valueString.length() - postfix.length(); assertEquals(valueString, value, Long.parseLong(valueString, start, end, radix)); - if (value > 0 && supportsPlusPrefix) { + if (value > 0) { valueString = prefix + "+" + Long.toString(value, radix) + postfix; end++; assertEquals(valueString, value, Long.parseLong(valueString, start, end, radix)); @@ -48,24 +48,29 @@ } try { - throw new AssertionError(Long.parseUnsignedLong("0", 0, 1, Character.MIN_RADIX - 1)); + throw new AssertionError(Long.parseLong("0", 0, 1, Character.MIN_RADIX - 1)); } catch (IllegalArgumentException expected) { } try { - throw new AssertionError(Long.parseUnsignedLong("0", 0, 1, Character.MAX_RADIX + 1)); + throw new AssertionError(Long.parseLong("0", 0, 1, Character.MAX_RADIX + 1)); } catch (IllegalArgumentException expected) { } try { - throw new AssertionError(Long.parseUnsignedLong("", 0, 0, 16)); + throw new AssertionError(Long.parseLong("", 0, 0, 16)); } catch (NumberFormatException expected) { } try { - throw new AssertionError(Long.parseUnsignedLong("-", 0, 1, 16)); + throw new AssertionError(Long.parseLong("-", 0, 1, 16)); } catch (NumberFormatException expected) { } try { - throw new AssertionError(Long.parseUnsignedLong("+", 0, 1, 16)); + throw new AssertionError(Long.parseLong("+", 0, 1, 16)); + } catch (NumberFormatException expected) { + } + + try { + throw new AssertionError(Long.parseLong("+a", 0, 2, 10)); } catch (NumberFormatException expected) { } @@ -122,6 +127,11 @@ } catch (NumberFormatException expected) { } + try { + throw new AssertionError(Long.parseUnsignedLong("+a", 0, 2, 10)); + } catch (NumberFormatException expected) { + } + BigInteger overflow = new BigInteger("18446744073709551616"); for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { for (String prefix : new String[] {"", "x", "xxx", "+", "x+", "xxx+"}) {
diff --git a/src/test/java/com/android/tools/r8/D8ApiBinaryCompatibilityTests.java b/src/test/java/com/android/tools/r8/D8ApiBinaryCompatibilityTests.java index 8e33480..8e5dd69 100644 --- a/src/test/java/com/android/tools/r8/D8ApiBinaryCompatibilityTests.java +++ b/src/test/java/com/android/tools/r8/D8ApiBinaryCompatibilityTests.java
@@ -95,7 +95,17 @@ ProcessBuilder builder = new ProcessBuilder(command); ProcessResult result = ToolHelper.runProcess(builder); assertEquals(result.stderr + "\n" + result.stdout, 0, result.exitCode); - Assert.assertTrue(result.stdout, result.stdout.isEmpty()); - Assert.assertTrue(result.stderr, result.stderr.isEmpty()); + Assert.assertEquals("", filterOutMainDexListWarnings(result.stdout)); + Assert.assertEquals("", result.stderr); + } + + public static String filterOutMainDexListWarnings(String output) { + StringBuilder builder = new StringBuilder(); + for (String line : output.split("\n")) { + if (!line.contains("Unsupported usage of main-dex list")) { + builder.append(line).append("\n"); + } + } + return builder.toString(); } }
diff --git a/src/test/java/com/android/tools/r8/DeviceRunner.java b/src/test/java/com/android/tools/r8/DeviceRunner.java index c68c8f2..fb46cfd 100644 --- a/src/test/java/com/android/tools/r8/DeviceRunner.java +++ b/src/test/java/com/android/tools/r8/DeviceRunner.java
@@ -167,7 +167,8 @@ throw new DeviceRunnerConfigurationException( "Running tests on more than one device is not yet supported. " + "Currently connected devices: [" - + StringUtils.join(Arrays.asList(connectedDevices), ",") + "]"); + + StringUtils.join(",", Arrays.asList(connectedDevices)) + + "]"); } int exitStatus = -1;
diff --git a/src/test/java/com/android/tools/r8/GenerateMainDexListTestBuilder.java b/src/test/java/com/android/tools/r8/GenerateMainDexListTestBuilder.java index 0700a5f..03ba4b8 100644 --- a/src/test/java/com/android/tools/r8/GenerateMainDexListTestBuilder.java +++ b/src/test/java/com/android/tools/r8/GenerateMainDexListTestBuilder.java
@@ -89,4 +89,9 @@ public GenerateMainDexListTestBuilder addDataEntryResources(DataEntryResource... resources) { return addDataResources(Arrays.asList(resources)); } + + public GenerateMainDexListTestBuilder setMainDexListOutputPath(Path output) { + builder.setMainDexListOutputPath(output); + return self(); + } }
diff --git a/src/test/java/com/android/tools/r8/R8ApiBinaryCompatibilityTests.java b/src/test/java/com/android/tools/r8/R8ApiBinaryCompatibilityTests.java index ac3d89f..67753da 100644 --- a/src/test/java/com/android/tools/r8/R8ApiBinaryCompatibilityTests.java +++ b/src/test/java/com/android/tools/r8/R8ApiBinaryCompatibilityTests.java
@@ -4,7 +4,6 @@ package com.android.tools.r8; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import com.android.tools.r8.ToolHelper.ProcessResult; import com.android.tools.r8.utils.AndroidApiLevel; @@ -82,7 +81,7 @@ ProcessBuilder builder = new ProcessBuilder(command); ProcessResult result = ToolHelper.runProcess(builder); assertEquals(result.stderr + "\n" + result.stdout, 0, result.exitCode); - assertTrue(result.stdout, result.stdout.isEmpty()); - assertTrue(result.stderr, result.stderr.isEmpty()); + assertEquals("", D8ApiBinaryCompatibilityTests.filterOutMainDexListWarnings(result.stdout)); + assertEquals("", result.stderr); } }
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java index e1d8658..0d90a34 100644 --- a/src/test/java/com/android/tools/r8/R8TestBuilder.java +++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -229,7 +229,7 @@ return addMainDexRuleFiles(Arrays.asList(files)); } - public T addMainDexClassRules(Class<?>... classes) { + public T addMainDexKeepClassRules(Class<?>... classes) { for (Class<?> clazz : classes) { addMainDexRules("-keep class " + clazz.getTypeName()); }
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java index ba56c6f..97b1a5c 100644 --- a/src/test/java/com/android/tools/r8/TestCompileResult.java +++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -477,7 +477,7 @@ .add(out.toString()) .build(); Consumer<ArtCommandBuilder> commandConsumer = - withArt6Plus64BitsLib && vm.getVersion().isAtLeast(DexVm.Version.V6_0_1) + withArt6Plus64BitsLib && vm.getVersion().isNewerThanOrEqual(DexVm.Version.V6_0_1) ? builder -> builder.appendArtOption("--64") : builder -> {}; commandConsumer =
diff --git a/src/test/java/com/android/tools/r8/TestParameters.java b/src/test/java/com/android/tools/r8/TestParameters.java index be45d1c..5a7423a 100644 --- a/src/test/java/com/android/tools/r8/TestParameters.java +++ b/src/test/java/com/android/tools/r8/TestParameters.java
@@ -36,6 +36,13 @@ .isGreaterThanOrEqualTo(TestBase.apiLevelWithDefaultInterfaceMethodsSupport()); } + public boolean canUseDefaultAndStaticInterfaceMethodsWhenDesugaring() { + assert isCfRuntime() || isDexRuntime(); + assert apiLevel != null; + return getApiLevel() + .isGreaterThanOrEqualTo(TestBase.apiLevelWithDefaultInterfaceMethodsSupport()); + } + // Convenience predicates. public boolean isDexRuntime() { return runtime.isDex(); @@ -49,6 +56,10 @@ return runtime.isCf() && runtime.asCf().getVm() == vm; } + public boolean isDexRuntimeVersion(DexVm.Version vm) { + return isDexRuntime() && vm == getDexRuntimeVersion(); + } + public boolean isNoneRuntime() { return runtime == NoneRuntime.getInstance(); }
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java index 7721c08..9d0e9b5 100644 --- a/src/test/java/com/android/tools/r8/ToolHelper.java +++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -180,10 +180,12 @@ public static final Path DESUGAR_LIB_CONVERSIONS = Paths.get(LIBS_DIR, "library_desugar_conversions.zip"); + public static final String DESUGAR_LIB_JSON_DIR = + System.getProperty("desugar_jdk_json_dir", "src/library_desugar"); public static final Path DESUGAR_LIB_JSON_FOR_TESTING = - Paths.get("src/library_desugar/desugar_jdk_libs.json"); + Paths.get(DESUGAR_LIB_JSON_DIR, "desugar_jdk_libs.json"); public static final Path DESUGAR_LIB_JSON_FOR_TESTING_ALTERNATIVE_3 = - Paths.get("src/library_desugar/desugar_jdk_libs_alternative_3.json"); + Paths.get(DESUGAR_LIB_JSON_DIR, "desugar_jdk_libs_alternative_3.json"); public static boolean isLocalDevelopment() { return System.getProperty("local_development", "0").equals("1"); @@ -266,7 +268,7 @@ } public boolean isLatest() { - return this == V10_0_0; + return this == last(); } public boolean isNewerThan(Version other) { @@ -277,10 +279,6 @@ return compareTo(other) >= 0; } - public boolean isAtLeast(Version other) { - return compareTo(other) >= 0; - } - public boolean isOlderThan(Version other) { return compareTo(other) < 0; } @@ -289,11 +287,16 @@ return compareTo(other) <= 0; } + public boolean isInRangeInclusive(Version start, Version end) { + assert start.isOlderThanOrEqual(end); + return isNewerThanOrEqual(start) && isOlderThanOrEqual(end); + } + public String toString() { return shortName; } - private String shortName; + private final String shortName; public static Version first() { return V4_0_4;
diff --git a/src/test/java/com/android/tools/r8/VmTestRunner.java b/src/test/java/com/android/tools/r8/VmTestRunner.java index a3e76a4..e2028a4 100644 --- a/src/test/java/com/android/tools/r8/VmTestRunner.java +++ b/src/test/java/com/android/tools/r8/VmTestRunner.java
@@ -78,7 +78,7 @@ IgnoreIfVmOlderThan ignoreIfVmOlderThan = child.getAnnotation(IgnoreIfVmOlderThan.class); if (ignoreIfVmOlderThan != null - && !currentVersion.isAtLeast(ignoreIfVmOlderThan.value())) { + && !currentVersion.isNewerThanOrEqual(ignoreIfVmOlderThan.value())) { return true; } IgnoreIfVmOlderOrEqualThan ignoreIfVmOlderOrEqualThan =
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerBottomTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerBottomTest.java index 3c71dbe..6dc8328 100644 --- a/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerBottomTest.java +++ b/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerBottomTest.java
@@ -4,6 +4,10 @@ package com.android.tools.r8.accessrelaxation; +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; + import com.android.tools.r8.NeverClassInline; import com.android.tools.r8.NeverInline; import com.android.tools.r8.NoVerticalClassMerging; @@ -12,6 +16,8 @@ import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.TestRunResult; import com.android.tools.r8.utils.DescriptorUtils; +import com.android.tools.r8.utils.codeinspector.ClassSubject; +import com.android.tools.r8.utils.codeinspector.MethodSubject; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -58,8 +64,17 @@ .enableNeverClassInliningAnnotations() .allowAccessModification() .run(parameters.getRuntime(), Main.class) - // TODO(b/181328496): This should be EXPECTED. - .assertSuccessWithOutputLines(EXPECTED_ART_4); + // TODO(b/182185057): This is an error in the devirtualizer + .assertSuccessWithOutputLines(EXPECTED_ART_4) + .inspect( + inspector -> { + ClassSubject subViewModelSubject = + inspector.clazz(DescriptorUtils.descriptorToJavaType(NEW_DESCRIPTOR)); + assertThat(subViewModelSubject, isPresent()); + MethodSubject clearSubject = subViewModelSubject.uniqueMethodWithName("clear"); + assertThat(clearSubject, isPresent()); + assertTrue(clearSubject.isPublic()); + }); } private byte[] getSubViewModelInAnotherPackage() throws Exception {
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerTest.java index 5a9da04..ccd0b21 100644 --- a/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerTest.java +++ b/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerTest.java
@@ -23,7 +23,6 @@ private final TestParameters parameters; private final String[] EXPECTED = new String[] {"SubViewModel.clear()", "ViewModel.clear()"}; - private final String[] R8_OUT = new String[] {"SubViewModel.clear()", "SubViewModel.clear()"}; @Parameters(name = "{0}") public static TestParametersCollection data() { @@ -52,8 +51,7 @@ .enableNeverClassInliningAnnotations() .allowAccessModification() .run(parameters.getRuntime(), Main.class) - // TODO(b/172496438): This should be EXPECTED. - .assertSuccessWithOutputLines(R8_OUT); + .apply(this::assertSuccessOutput); } private void assertSuccessOutput(TestRunResult<?> result) {
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedInstanceOfTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedInstanceOfTest.java index 30b2a78..492e21e 100644 --- a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedInstanceOfTest.java +++ b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedInstanceOfTest.java
@@ -59,7 +59,7 @@ @Test() public void testD8Dex() throws Exception { assumeTrue(parameters.isDexRuntime()); - boolean expectFailure = parameters.getDexRuntimeVersion().isAtLeast(Version.V7_0_0); + boolean expectFailure = parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V7_0_0); testForD8(parameters.getBackend()) .addProgramClassFileData(dump()) .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java b/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java index fcc79dc..2c58d15 100644 --- a/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java +++ b/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java
@@ -111,7 +111,7 @@ continue; } String holderName = method.getHolderType().getName(); - String methodName = method.method.name.toString(); + String methodName = method.getReference().name.toString(); String generatedMethodName = holderName + "_" + methodName; CfCode code = getCode(holderName, methodName, method.getCode().asCfCode()); if (code != null) {
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingNonTrivialTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingNonTrivialTest.java index 42df5c0..fbd058a 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingNonTrivialTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingNonTrivialTest.java
@@ -12,9 +12,8 @@ public class AbstractMethodMergingNonTrivialTest extends HorizontalClassMergingTestBase { - public AbstractMethodMergingNonTrivialTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public AbstractMethodMergingNonTrivialTest(TestParameters parameters) { + super(parameters); } @Test @@ -22,11 +21,8 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .enableInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() .enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingTest.java index 3b0af4f..a30ca9e 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingTest.java
@@ -12,9 +12,8 @@ public class AbstractMethodMergingTest extends HorizontalClassMergingTestBase { - public AbstractMethodMergingTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public AbstractMethodMergingTest(TestParameters parameters) { + super(parameters); } @Test @@ -22,11 +21,8 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .enableInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() .enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptResourceFileContentsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptResourceFileContentsTest.java index db8d4c7..cdd0df8 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptResourceFileContentsTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptResourceFileContentsTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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 static org.junit.Assert.assertEquals; @@ -23,9 +23,8 @@ import org.junit.Test; public class AdaptResourceFileContentsTest extends HorizontalClassMergingTestBase { - public AdaptResourceFileContentsTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public AdaptResourceFileContentsTest(TestParameters parameters) { + super(parameters); } @Test @@ -35,9 +34,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .addOptionsModification(options -> options.dataResourceConsumer = dataResourceConsumer) .enableNeverClassInliningAnnotations() .addDataEntryResources( @@ -45,8 +41,7 @@ "foo.txt", Origin.unknown(), A.class.getTypeName(), B.class.getTypeName())) .addKeepRules("-adaptresourcefilecontents foo.txt") .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> inspector.assertMergedInto(B.class, A.class)) .compile() .run(parameters.getRuntime(), Main.class) @@ -57,11 +52,10 @@ assertThat(aClassSubject, isPresent()); ClassSubject bClassSubject = codeInspector.clazz(B.class); - assertThat(bClassSubject, notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(bClassSubject, isAbsent()); // Check that the class name has been rewritten. - String newClassBName = - (enableHorizontalClassMerging ? aClassSubject : bClassSubject).getFinalName(); + String newClassBName = aClassSubject.getFinalName(); assertEquals( dataResourceConsumer.get("foo.txt"), ImmutableList.of(aClassSubject.getFinalName(), newClassBName));
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptVerticallyMergedResourceFileContentsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptVerticallyMergedResourceFileContentsTest.java index 090cb9e..1cbf805 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptVerticallyMergedResourceFileContentsTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptVerticallyMergedResourceFileContentsTest.java
@@ -5,7 +5,6 @@ package com.android.tools.r8.classmerging.horizontal; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; -import static com.android.tools.r8.utils.codeinspector.Matchers.notIf; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; @@ -21,9 +20,8 @@ import org.junit.Test; public class AdaptVerticallyMergedResourceFileContentsTest extends HorizontalClassMergingTestBase { - public AdaptVerticallyMergedResourceFileContentsTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public AdaptVerticallyMergedResourceFileContentsTest(TestParameters parameters) { + super(parameters); } @Test @@ -33,9 +31,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .addOptionsModification(options -> options.dataResourceConsumer = dataResourceConsumer) .enableNeverClassInliningAnnotations() .addDataEntryResources( @@ -47,8 +42,7 @@ B.class.getTypeName())) .addKeepRules("-adaptresourcefilecontents foo.txt") .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> inspector.assertMergedInto(B.class, A.class)) .addVerticallyMergedClassesInspector( inspector -> inspector.assertMergedIntoSubtype(Parent.class)) @@ -63,11 +57,10 @@ assertThat(aClassSubject, isPresent()); ClassSubject bClassSubject = codeInspector.clazz(B.class); - assertThat(bClassSubject, notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(bClassSubject, not(isPresent())); // Check that the class name has been rewritten. - String newClassName = - (enableHorizontalClassMerging ? aClassSubject : bClassSubject).getFinalName(); + String newClassName = aClassSubject.getFinalName(); assertEquals( dataResourceConsumer.get("foo.txt"), ImmutableList.of(aClassSubject.getFinalName(), aClassSubject.getFinalName(), newClassName));
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassWithInstanceFieldsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassWithInstanceFieldsTest.java index 31a49cc..41071d8 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassWithInstanceFieldsTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassWithInstanceFieldsTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -14,9 +14,8 @@ import org.junit.Test; public class ClassWithInstanceFieldsTest extends HorizontalClassMergingTestBase { - public ClassWithInstanceFieldsTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ClassWithInstanceFieldsTest(TestParameters parameters) { + super(parameters); } @Test @@ -24,21 +23,17 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .enableInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("A. field: 5, v: a, j: 1", "B. field: b, v: 2, j: 3") .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectCheckCastTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectCheckCastTest.java index bc5380e..bbf9149 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectCheckCastTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectCheckCastTest.java
@@ -13,9 +13,8 @@ import org.junit.Test; public class ClassesDistinguishedByDirectCheckCastTest extends HorizontalClassMergingTestBase { - public ClassesDistinguishedByDirectCheckCastTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ClassesDistinguishedByDirectCheckCastTest(TestParameters parameters) { + super(parameters); } @Test @@ -23,9 +22,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectInstanceOfTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectInstanceOfTest.java index 6551ad2..d380c43 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectInstanceOfTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectInstanceOfTest.java
@@ -13,9 +13,8 @@ import org.junit.Test; public class ClassesDistinguishedByDirectInstanceOfTest extends HorizontalClassMergingTestBase { - public ClassesDistinguishedByDirectInstanceOfTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ClassesDistinguishedByDirectInstanceOfTest(TestParameters parameters) { + super(parameters); } @Test @@ -23,9 +22,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java index 6017cbe..9847ac8 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java
@@ -15,9 +15,8 @@ public class ClassesDistinguishedByIndirectCheckCastToInterfaceTest extends HorizontalClassMergingTestBase { - public ClassesDistinguishedByIndirectCheckCastToInterfaceTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ClassesDistinguishedByIndirectCheckCastToInterfaceTest(TestParameters parameters) { + super(parameters); } @Test @@ -25,9 +24,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNoVerticalClassMergingAnnotations() .enableInliningAnnotations() .enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java index cf05da6..8bf955c 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java
@@ -15,9 +15,8 @@ public class ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast extends HorizontalClassMergingTestBase { - public ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast(TestParameters parameters) { + super(parameters); } @Test @@ -25,9 +24,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNoVerticalClassMergingAnnotations() .enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentFieldsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentFieldsTest.java index d322729..7e90337 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentFieldsTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentFieldsTest.java
@@ -6,8 +6,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -16,9 +16,8 @@ import org.junit.Test; public class ClassesWithDifferentFieldsTest extends HorizontalClassMergingTestBase { - public ClassesWithDifferentFieldsTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ClassesWithDifferentFieldsTest(TestParameters parameters) { + super(parameters); } @Test @@ -26,22 +25,18 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .enableInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .compile() .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("A. v: a", "B. i: 2") .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentInterfacesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentInterfacesTest.java index 5abdc09..497e4df 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentInterfacesTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentInterfacesTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -15,9 +15,8 @@ import org.junit.Test; public class ClassesWithDifferentInterfacesTest extends HorizontalClassMergingTestBase { - public ClassesWithDifferentInterfacesTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ClassesWithDifferentInterfacesTest(TestParameters parameters) { + super(parameters); } @Test @@ -25,15 +24,12 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(Z.class, Y.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(Z.class, Y.class)) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("bar", "foo y", "bar") .inspect( @@ -41,8 +37,7 @@ assertThat(codeInspector.clazz(I.class), isPresent()); assertThat(codeInspector.clazz(X.class), isPresent()); assertThat(codeInspector.clazz(Y.class), isPresent()); - assertThat( - codeInspector.clazz(Z.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(Z.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentVisibilityFieldsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentVisibilityFieldsTest.java index 68a81b1..269b793 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentVisibilityFieldsTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentVisibilityFieldsTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; -import static com.android.tools.r8.utils.codeinspector.Matchers.notIf; import static com.android.tools.r8.utils.codeinspector.Matchers.readsInstanceField; import static org.hamcrest.MatcherAssert.assertThat; @@ -21,9 +21,8 @@ import org.junit.Test; public class ClassesWithDifferentVisibilityFieldsTest extends HorizontalClassMergingTestBase { - public ClassesWithDifferentVisibilityFieldsTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ClassesWithDifferentVisibilityFieldsTest(TestParameters parameters) { + super(parameters); } @Test @@ -31,14 +30,11 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines( "a. v1: 10, v2: 20", "b. v1: 60, v2: 100", "c. v1: 210, v2: 330") @@ -46,31 +42,28 @@ codeInspector -> { ClassSubject aClassSubject = codeInspector.clazz(A.class); assertThat(aClassSubject, isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); assertThat(codeInspector.clazz(C.class), isPresent()); - if (enableHorizontalClassMerging) { - FieldSubject v1Subject = aClassSubject.uniqueFieldWithName("v1"); - FieldSubject v2Subject = aClassSubject.uniqueFieldWithName("v2"); + FieldSubject v1Subject = aClassSubject.uniqueFieldWithName("v1"); + FieldSubject v2Subject = aClassSubject.uniqueFieldWithName("v2"); - MethodSubject methodSubject = aClassSubject.uniqueMethodWithName("getAV1"); - assertThat(methodSubject, isPresent()); - assertThat(methodSubject, readsInstanceField(v1Subject.getDexField())); + MethodSubject methodSubject = aClassSubject.uniqueMethodWithName("getAV1"); + assertThat(methodSubject, isPresent()); + assertThat(methodSubject, readsInstanceField(v1Subject.getDexField())); - methodSubject = aClassSubject.uniqueMethodWithName("getAV2"); - assertThat(methodSubject, isPresent()); - assertThat(methodSubject, readsInstanceField(v2Subject.getDexField())); + methodSubject = aClassSubject.uniqueMethodWithName("getAV2"); + assertThat(methodSubject, isPresent()); + assertThat(methodSubject, readsInstanceField(v2Subject.getDexField())); - // The fields v1 and v2 are swapped, because their access modifiers are swapped. - methodSubject = aClassSubject.uniqueMethodWithName("getBV1"); - assertThat(methodSubject, isPresent()); - assertThat(methodSubject, readsInstanceField(v2Subject.getDexField())); + // The fields v1 and v2 are swapped, because their access modifiers are swapped. + methodSubject = aClassSubject.uniqueMethodWithName("getBV1"); + assertThat(methodSubject, isPresent()); + assertThat(methodSubject, readsInstanceField(v2Subject.getDexField())); - methodSubject = aClassSubject.uniqueMethodWithName("getBV2"); - assertThat(methodSubject, isPresent()); - assertThat(methodSubject, readsInstanceField(v1Subject.getDexField())); - } + methodSubject = aClassSubject.uniqueMethodWithName("getBV2"); + assertThat(methodSubject, isPresent()); + assertThat(methodSubject, readsInstanceField(v1Subject.getDexField())); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithFeatureSplitTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithFeatureSplitTest.java index 9ac569b..3f0fac0 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithFeatureSplitTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithFeatureSplitTest.java
@@ -5,30 +5,26 @@ package com.android.tools.r8.classmerging.horizontal; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; -import static com.android.tools.r8.utils.codeinspector.Matchers.notIf; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import com.android.tools.r8.NeverClassInline; import com.android.tools.r8.R8TestCompileResult; import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.dexsplitter.SplitterTestBase.RunInterface; -import com.android.tools.r8.utils.BooleanUtils; import com.android.tools.r8.utils.codeinspector.CodeInspector; -import java.util.List; import org.junit.Test; import org.junit.runners.Parameterized; public class ClassesWithFeatureSplitTest extends HorizontalClassMergingTestBase { - public ClassesWithFeatureSplitTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ClassesWithFeatureSplitTest(TestParameters parameters) { + super(parameters); } - @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") - public static List<Object[]> data() { - return buildParameters( - getTestParameters().withDexRuntimes().withAllApiLevels().build(), BooleanUtils.values()); + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withDexRuntimes().withAllApiLevels().build(); } @Test @@ -41,9 +37,6 @@ .addFeatureSplit(Feature2Class.class, Feature2Main.class) .addKeepFeatureMainRule(Feature1Main.class) .addKeepFeatureMainRule(Feature2Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) .compile() @@ -68,8 +61,7 @@ private void inspectFeature1(CodeInspector inspector) { assertThat(inspector.clazz(Feature1Main.class), isPresent()); assertThat(inspector.clazz(Feature1Class1.class), isPresent()); - assertThat( - inspector.clazz(Feature1Class2.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(inspector.clazz(Feature1Class2.class), not(isPresent())); assertThat(inspector.clazz(Feature2Main.class), not(isPresent())); assertThat(inspector.clazz(Feature2Class.class), not(isPresent())); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithIdenticalInterfacesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithIdenticalInterfacesTest.java index 6714388..9a5f503 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithIdenticalInterfacesTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithIdenticalInterfacesTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -14,9 +14,8 @@ import org.junit.Test; public class ClassesWithIdenticalInterfacesTest extends HorizontalClassMergingTestBase { - public ClassesWithIdenticalInterfacesTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ClassesWithIdenticalInterfacesTest(TestParameters parameters) { + super(parameters); } @Test @@ -24,14 +23,10 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> inspector.assertMergedInto(Y.class, X.class).assertMergedInto(Z.class, X.class)) .run(parameters.getRuntime(), Main.class) @@ -40,10 +35,8 @@ codeInspector -> { assertThat(codeInspector.clazz(I.class), isPresent()); assertThat(codeInspector.clazz(X.class), isPresent()); - assertThat( - codeInspector.clazz(Y.class), notIf(isPresent(), enableHorizontalClassMerging)); - assertThat( - codeInspector.clazz(Z.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(Y.class), isAbsent()); + assertThat(codeInspector.clazz(Z.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithNativeMethodsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithNativeMethodsTest.java index c551a26..dcdd8f8 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithNativeMethodsTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithNativeMethodsTest.java
@@ -16,9 +16,8 @@ import org.junit.Test; public class ClassesWithNativeMethodsTest extends HorizontalClassMergingTestBase { - public ClassesWithNativeMethodsTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ClassesWithNativeMethodsTest(TestParameters parameters) { + super(parameters); } @Test @@ -26,9 +25,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithOverlappingVisibilitiesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithOverlappingVisibilitiesTest.java index 608f6fe..db0ce63 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithOverlappingVisibilitiesTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithOverlappingVisibilitiesTest.java
@@ -4,10 +4,10 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; import static com.android.tools.r8.utils.codeinspector.Matchers.isPackagePrivate; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static com.android.tools.r8.utils.codeinspector.Matchers.isPublic; -import static com.android.tools.r8.utils.codeinspector.Matchers.notIf; import static org.hamcrest.MatcherAssert.assertThat; import com.android.tools.r8.NeverClassInline; @@ -18,9 +18,8 @@ import org.junit.Test; public class ClassesWithOverlappingVisibilitiesTest extends HorizontalClassMergingTestBase { - public ClassesWithOverlappingVisibilitiesTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ClassesWithOverlappingVisibilitiesTest(TestParameters parameters) { + super(parameters); } @Test @@ -28,9 +27,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -45,23 +41,18 @@ ClassSubject bClassSubject = codeInspector.clazz(B.class); assertThat(bClassSubject, isPresent()); - if (enableHorizontalClassMerging) { - methodSubject = bClassSubject.method("void", "foo$bridge"); - assertThat(methodSubject, isPackagePrivate()); - } + methodSubject = bClassSubject.method("void", "foo$bridge"); + assertThat(methodSubject, isPackagePrivate()); - assertThat( - codeInspector.clazz(C.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(C.class), isAbsent()); ClassSubject dClassSubject = codeInspector.clazz(D.class); assertThat(dClassSubject, isPresent()); - if (enableHorizontalClassMerging) { - methodSubject = dClassSubject.method("void", "foo$bridge"); - assertThat(methodSubject, isPublic()); - } + methodSubject = dClassSubject.method("void", "foo$bridge"); + assertThat(methodSubject, isPublic()); ClassSubject eClassSubject = codeInspector.clazz(E.class); - assertThat(eClassSubject, notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(eClassSubject, isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithStaticFields.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithStaticFields.java index 2810ce8..d66a630 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithStaticFields.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithStaticFields.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -13,8 +13,8 @@ import org.junit.Test; public class ClassesWithStaticFields extends HorizontalClassMergingTestBase { - public ClassesWithStaticFields(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ClassesWithStaticFields(TestParameters parameters) { + super(parameters); } @Test @@ -22,20 +22,16 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("a: 0", "b: 0", "a: 1", "b: 1") .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/CompanionClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/CompanionClassMergingTest.java index 9aca9fe..364f7ed 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/CompanionClassMergingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/CompanionClassMergingTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -16,9 +16,8 @@ import org.junit.Test; public class CompanionClassMergingTest extends HorizontalClassMergingTestBase { - public CompanionClassMergingTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public CompanionClassMergingTest(TestParameters parameters) { + super(parameters); } @Test @@ -26,14 +25,10 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .addOptionsModification(options -> options.enableClassInlining = false) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> inspector.assertMergedInto(B.Companion.class, A.Companion.class)) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("foo a 0", "foo b 1") @@ -43,9 +38,7 @@ assertThat(codeInspector.clazz(B.class), isPresent()); assertThat(codeInspector.clazz(A.Companion.class), isPresent()); - assertThat( - codeInspector.clazz(B.Companion.class), - notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.Companion.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/CompatKeepConstructorLiveTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/CompatKeepConstructorLiveTest.java index c03361f..ccec2d8 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/CompatKeepConstructorLiveTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/CompatKeepConstructorLiveTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -14,9 +14,8 @@ import org.junit.Test; public class CompatKeepConstructorLiveTest extends HorizontalClassMergingTestBase { - public CompatKeepConstructorLiveTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public CompatKeepConstructorLiveTest(TestParameters parameters) { + super(parameters); } @Test @@ -24,9 +23,6 @@ testForR8Compat(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class) @@ -39,8 +35,7 @@ assertThat(aClassSubject.init(), isPresent()); assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java index 369ebfd..07cea40 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java
@@ -5,20 +5,17 @@ package com.android.tools.r8.classmerging.horizontal; 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 static org.hamcrest.core.IsNot.not; import com.android.tools.r8.NeverClassInline; import com.android.tools.r8.NeverInline; -import com.android.tools.r8.NoHorizontalClassMerging; import com.android.tools.r8.TestParameters; import org.junit.Test; public class ConstructorCantInlineTest extends HorizontalClassMergingTestBase { - public ConstructorCantInlineTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ConstructorCantInlineTest(TestParameters parameters) { + super(parameters); } @Test @@ -26,9 +23,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -39,8 +33,7 @@ assertThat(codeInspector.clazz(A.class), not(isPresent())); assertThat(codeInspector.clazz(B.class), isPresent()); assertThat(codeInspector.clazz(C.class), isPresent()); - assertThat( - codeInspector.clazz(D.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(D.class), not(isPresent())); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingAfterUnusedArgumentRemovalTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingAfterUnusedArgumentRemovalTest.java index d38efb3..fd1a5ac 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingAfterUnusedArgumentRemovalTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingAfterUnusedArgumentRemovalTest.java
@@ -11,9 +11,8 @@ public class ConstructorMergingAfterUnusedArgumentRemovalTest extends HorizontalClassMergingTestBase { - public ConstructorMergingAfterUnusedArgumentRemovalTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ConstructorMergingAfterUnusedArgumentRemovalTest(TestParameters parameters) { + super(parameters); } @Test @@ -21,13 +20,9 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> inspector .assertMergedInto(B.class, A.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java index 8936dc1..055ab8d 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java
@@ -21,9 +21,8 @@ public class ConstructorMergingOverlapTest extends HorizontalClassMergingTestBase { - public ConstructorMergingOverlapTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ConstructorMergingOverlapTest(TestParameters parameters) { + super(parameters); } @Test @@ -31,9 +30,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -41,7 +37,6 @@ .assertSuccessWithOutputLines("42", "13", "7", "print a", "print b") .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { ClassSubject aClassSubject = codeInspector.clazz(A.class); assertThat(aClassSubject, isPresent()); FieldSubject classIdFieldSubject = @@ -66,12 +61,6 @@ assertThat(printSubject, readsInstanceField(classIdFieldSubject.getDexField())); assertThat(codeInspector.clazz(B.class), not(isPresent())); - - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java index 4d62a05..e0c6c9e 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java
@@ -22,9 +22,8 @@ public class ConstructorMergingPreoptimizedTest extends HorizontalClassMergingTestBase { - public ConstructorMergingPreoptimizedTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ConstructorMergingPreoptimizedTest(TestParameters parameters) { + super(parameters); } @Test @@ -32,11 +31,8 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() @@ -46,38 +42,29 @@ "changed", "13", "42", "foo", "7", "foo", "print a", "print b") .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { - ClassSubject changedClassSubject = codeInspector.clazz(Changed.class); - assertThat(changedClassSubject, isPresent()); + ClassSubject changedClassSubject = codeInspector.clazz(Changed.class); + assertThat(changedClassSubject, isPresent()); - ClassSubject aClassSubject = codeInspector.clazz(A.class); - assertThat(aClassSubject, isPresent()); - FieldSubject classIdFieldSubject = - aClassSubject.uniqueFieldWithName(ClassMerger.CLASS_ID_FIELD_NAME); - assertThat(classIdFieldSubject, isPresent()); + ClassSubject aClassSubject = codeInspector.clazz(A.class); + assertThat(aClassSubject, isPresent()); + FieldSubject classIdFieldSubject = + aClassSubject.uniqueFieldWithName(ClassMerger.CLASS_ID_FIELD_NAME); + assertThat(classIdFieldSubject, isPresent()); - MethodSubject firstInitSubject = aClassSubject.init("int"); - assertThat(firstInitSubject, isPresent()); - assertThat( - firstInitSubject, writesInstanceField(classIdFieldSubject.getDexField())); + MethodSubject firstInitSubject = aClassSubject.init("int"); + assertThat(firstInitSubject, isPresent()); + assertThat(firstInitSubject, writesInstanceField(classIdFieldSubject.getDexField())); - MethodSubject otherInitSubject = - aClassSubject.init(changedClassSubject.getFinalName(), "int"); - assertThat(otherInitSubject, isPresent()); - assertThat( - otherInitSubject, writesInstanceField(classIdFieldSubject.getDexField())); + MethodSubject otherInitSubject = + aClassSubject.init(changedClassSubject.getFinalName(), "int"); + assertThat(otherInitSubject, isPresent()); + assertThat(otherInitSubject, writesInstanceField(classIdFieldSubject.getDexField())); - MethodSubject printSubject = aClassSubject.method("void", "print$bridge"); - assertThat(printSubject, isPresent()); - assertThat(printSubject, readsInstanceField(classIdFieldSubject.getDexField())); + MethodSubject printSubject = aClassSubject.method("void", "print$bridge"); + assertThat(printSubject, isPresent()); + assertThat(printSubject, readsInstanceField(classIdFieldSubject.getDexField())); - assertThat(codeInspector.clazz(B.class), not(isPresent())); - - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - } + assertThat(codeInspector.clazz(B.class), not(isPresent())); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTest.java index 21c3486..b76442b 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTest.java
@@ -13,8 +13,8 @@ import org.junit.Test; public class ConstructorMergingTest extends HorizontalClassMergingTestBase { - public ConstructorMergingTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ConstructorMergingTest(TestParameters parameters) { + super(parameters); } @Test @@ -22,23 +22,14 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("foo", "bar") .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { assertThat(codeInspector.clazz(A.class), isPresent()); assertThat(codeInspector.clazz(B.class), not(isPresent())); - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java index 50da81e..0dd1f3e 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java
@@ -21,9 +21,8 @@ public class ConstructorMergingTrivialOverlapTest extends HorizontalClassMergingTestBase { - public ConstructorMergingTrivialOverlapTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ConstructorMergingTrivialOverlapTest(TestParameters parameters) { + super(parameters); } @Test @@ -31,9 +30,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -41,7 +37,6 @@ .assertSuccessWithOutputLines("7", "42", "13", "print a", "print b") .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { ClassSubject aClassSubject = codeInspector.clazz(A.class); assertThat(aClassSubject, isPresent()); FieldSubject classIdFieldSubject = @@ -66,12 +61,6 @@ assertThat(printSubject, readsInstanceField(classIdFieldSubject.getDexField())); assertThat(codeInspector.clazz(B.class), not(isPresent())); - - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingWithArgumentsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingWithArgumentsTest.java index 7891de2..30a84ca 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingWithArgumentsTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingWithArgumentsTest.java
@@ -15,9 +15,8 @@ import org.junit.Test; public class ConstructorMergingWithArgumentsTest extends HorizontalClassMergingTestBase { - public ConstructorMergingWithArgumentsTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ConstructorMergingWithArgumentsTest(TestParameters parameters) { + super(parameters); } @Test @@ -25,16 +24,12 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("foo hello", "bar world") .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { ClassSubject aClassSubject = codeInspector.clazz(A.class); assertThat(aClassSubject, isPresent()); @@ -42,11 +37,6 @@ MethodSubject initSubject = aClassSubject.init(String.class.getName(), "int"); assertThat(initSubject, isPresent()); - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/DistinguishExceptionClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/DistinguishExceptionClassesTest.java index 749ae58..e063a4b 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/DistinguishExceptionClassesTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/DistinguishExceptionClassesTest.java
@@ -11,9 +11,8 @@ import org.junit.Test; public class DistinguishExceptionClassesTest extends HorizontalClassMergingTestBase { - public DistinguishExceptionClassesTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public DistinguishExceptionClassesTest(TestParameters parameters) { + super(parameters); } @Test @@ -21,9 +20,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("test success")
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/EmptyClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/EmptyClassTest.java index 5d63188..d33b180 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/EmptyClassTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/EmptyClassTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -15,8 +15,8 @@ import org.junit.Test; public class EmptyClassTest extends HorizontalClassMergingTestBase { - public EmptyClassTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public EmptyClassTest(TestParameters parameters) { + super(parameters); } @Test @@ -24,20 +24,16 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("a", "b: foo") .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/FieldTypeMergedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/FieldTypeMergedTest.java index 58434a9..e688559 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/FieldTypeMergedTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/FieldTypeMergedTest.java
@@ -4,10 +4,10 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; import static com.android.tools.r8.utils.codeinspector.Matchers.isFieldOfArrayType; import static com.android.tools.r8.utils.codeinspector.Matchers.isFieldOfType; 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 static org.junit.Assert.assertTrue; @@ -19,8 +19,8 @@ import org.junit.Test; public class FieldTypeMergedTest extends HorizontalClassMergingTestBase { - public FieldTypeMergedTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public FieldTypeMergedTest(TestParameters parameters) { + super(parameters); } @Test @@ -28,9 +28,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -40,28 +37,21 @@ codeInspector -> { ClassSubject aClassSubject = codeInspector.clazz(A.class); assertThat(aClassSubject, isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); ClassSubject cClassSubject = codeInspector.clazz(C.class); assertThat(codeInspector.clazz(C.class), isPresent()); FieldSubject fieldSubject = cClassSubject.uniqueFieldWithName("fieldB"); assertThat(fieldSubject, isPresent()); - if (enableHorizontalClassMerging) { - assertThat( - fieldSubject, isFieldOfType(aClassSubject.getDexProgramClass().getType())); - } + assertThat(fieldSubject, isFieldOfType(aClassSubject.getDexProgramClass().getType())); fieldSubject = cClassSubject.uniqueFieldWithName("fieldArrayB"); assertThat(fieldSubject, isPresent()); assertTrue(fieldSubject.getDexField().type.isArrayType()); - if (enableHorizontalClassMerging) { - assertThat( - fieldSubject, - isFieldOfArrayType( - codeInspector, aClassSubject.getDexProgramClass().getType())); - } + assertThat( + fieldSubject, + isFieldOfArrayType(codeInspector, aClassSubject.getDexProgramClass().getType())); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/FieldsWithDifferentAccessFlagsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/FieldsWithDifferentAccessFlagsTest.java index 58acdbf..7468ce5 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/FieldsWithDifferentAccessFlagsTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/FieldsWithDifferentAccessFlagsTest.java
@@ -14,9 +14,8 @@ public class FieldsWithDifferentAccessFlagsTest extends HorizontalClassMergingTestBase { - public FieldsWithDifferentAccessFlagsTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public FieldsWithDifferentAccessFlagsTest(TestParameters parameters) { + super(parameters); } @Test @@ -24,11 +23,8 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, HorizontallyMergedClassesInspector::assertNoClassesMerged) + .addHorizontallyMergedClassesInspector( + HorizontallyMergedClassesInspector::assertNoClassesMerged) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/GenericStaticFieldTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/GenericStaticFieldTest.java index af72afe..e1248e1 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/GenericStaticFieldTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/GenericStaticFieldTest.java
@@ -9,8 +9,8 @@ import org.junit.Test; public class GenericStaticFieldTest extends HorizontalClassMergingTestBase { - public GenericStaticFieldTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public GenericStaticFieldTest(TestParameters parameters) { + super(parameters); } @Test @@ -19,9 +19,6 @@ .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .addKeepRules("-keepattributes Signatures") - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) // .addHorizontallyMergedClassesInspectorIf(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingTestBase.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingTestBase.java index 5b2dbe7..fa19056 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingTestBase.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingTestBase.java
@@ -6,29 +6,25 @@ import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.synthesis.SyntheticItemsTestUtils; -import com.android.tools.r8.utils.BooleanUtils; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; -import java.util.List; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(Parameterized.class) public abstract class HorizontalClassMergingTestBase extends TestBase { - protected final TestParameters parameters; - protected final boolean enableHorizontalClassMerging; - protected HorizontalClassMergingTestBase( - TestParameters parameters, boolean enableHorizontalClassMerging) { + protected final TestParameters parameters; + + protected HorizontalClassMergingTestBase(TestParameters parameters) { this.parameters = parameters; - this.enableHorizontalClassMerging = enableHorizontalClassMerging; } - @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") - public static List<Object[]> data() { - return buildParameters( - getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values()); + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); } protected ClassSubject getSynthesizedArgumentClassSubject(CodeInspector codeInspector) {
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/IdenticalFieldMembersTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/IdenticalFieldMembersTest.java index 9dae7a2..08a3bd7 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/IdenticalFieldMembersTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/IdenticalFieldMembersTest.java
@@ -4,17 +4,16 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.*; import org.junit.Test; public class IdenticalFieldMembersTest extends HorizontalClassMergingTestBase { - public IdenticalFieldMembersTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public IdenticalFieldMembersTest(TestParameters parameters) { + super(parameters); } @Test @@ -22,9 +21,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -33,8 +29,7 @@ .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritInterfaceWithDefaultTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritInterfaceWithDefaultTest.java index b069bb1..ef0cedf 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritInterfaceWithDefaultTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritInterfaceWithDefaultTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -18,9 +18,8 @@ public class InheritInterfaceWithDefaultTest extends HorizontalClassMergingTestBase { - public InheritInterfaceWithDefaultTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public InheritInterfaceWithDefaultTest(TestParameters parameters) { + super(parameters); } @Test @@ -29,22 +28,18 @@ .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .allowStdoutMessages() - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines( "print interface", "print interface", "print interface", "print interface") .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritOverrideInterfaceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritOverrideInterfaceTest.java index 8c7644d..8bea286 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritOverrideInterfaceTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritOverrideInterfaceTest.java
@@ -13,9 +13,8 @@ import org.junit.Test; public class InheritOverrideInterfaceTest extends HorizontalClassMergingTestBase { - public InheritOverrideInterfaceTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public InheritOverrideInterfaceTest(TestParameters parameters) { + super(parameters); } @Test @@ -23,14 +22,11 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNoVerticalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("A", "B", "A") .inspect(codeInspector -> {});
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritsFromLibraryClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritsFromLibraryClassTest.java index 575c2cd..33a1909 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritsFromLibraryClassTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritsFromLibraryClassTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -19,9 +19,8 @@ import org.junit.Test; public class InheritsFromLibraryClassTest extends HorizontalClassMergingTestBase { - public InheritsFromLibraryClassTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public InheritsFromLibraryClassTest(TestParameters parameters) { + super(parameters); } @Test @@ -29,9 +28,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -41,8 +37,7 @@ codeInspector -> { assertThat(codeInspector.clazz(Parent.class), isPresent()); assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); assertThat(codeInspector.clazz(C.class), isPresent()); }); } @@ -74,7 +69,7 @@ } @NeverClassInline - public static class C extends ArrayList { + public static class C extends ArrayList<Object> { public C() {} public void fooB(B b) {
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/InnerOuterClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/InnerOuterClassesTest.java index 98e74e4..a6a93ad 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/InnerOuterClassesTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/InnerOuterClassesTest.java
@@ -12,8 +12,8 @@ import org.junit.Test; public class InnerOuterClassesTest extends HorizontalClassMergingTestBase { - public InnerOuterClassesTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public InnerOuterClassesTest(TestParameters parameters) { + super(parameters); } @Test @@ -21,9 +21,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .addKeepAttributes("InnerClasses", "EnclosingMethod") .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/InstantiatedAndUninstantiatedClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/InstantiatedAndUninstantiatedClassMergingTest.java index 59e77dd..d6b6643 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/InstantiatedAndUninstantiatedClassMergingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/InstantiatedAndUninstantiatedClassMergingTest.java
@@ -16,9 +16,8 @@ public class InstantiatedAndUninstantiatedClassMergingTest extends HorizontalClassMergingTestBase { - public InstantiatedAndUninstantiatedClassMergingTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public InstantiatedAndUninstantiatedClassMergingTest(TestParameters parameters) { + super(parameters); } @Test @@ -35,9 +34,6 @@ testBuilder .addInnerClasses(getClass()) .addKeepMainRule(TestClass.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .addHorizontallyMergedClassesInspector(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/JavaLambdaMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/JavaLambdaMergingTest.java index f7aacb5..6f96433 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/JavaLambdaMergingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/JavaLambdaMergingTest.java
@@ -18,8 +18,8 @@ public class JavaLambdaMergingTest extends HorizontalClassMergingTestBase { - public JavaLambdaMergingTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public JavaLambdaMergingTest(TestParameters parameters) { + super(parameters); } @Test @@ -27,11 +27,8 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging && parameters.isDexRuntime(), + parameters.isDexRuntime(), inspector -> { Set<DexType> lambdaSources = inspector.getSources().stream()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/LargeConstructorsMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/LargeConstructorsMergingTest.java index a553abe..00b1f38 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/LargeConstructorsMergingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/LargeConstructorsMergingTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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 static org.junit.Assert.assertEquals; @@ -15,9 +15,8 @@ import org.junit.Test; public class LargeConstructorsMergingTest extends HorizontalClassMergingTestBase { - public LargeConstructorsMergingTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public LargeConstructorsMergingTest(TestParameters parameters) { + super(parameters); } @Test @@ -25,14 +24,10 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .addOptionsModification(options -> options.testing.verificationSizeLimitInBytesOverride = 4) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> inspector.assertMergedInto(B.class, A.class).assertMergedInto(C.class, A.class)) .run(parameters.getRuntime(), Main.class) @@ -41,15 +36,11 @@ codeInspector -> { ClassSubject aClassSubject = codeInspector.clazz(A.class); assertThat(aClassSubject, isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); - assertThat( - codeInspector.clazz(C.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); + assertThat(codeInspector.clazz(C.class), isAbsent()); - if (enableHorizontalClassMerging) { - // There should be three constructors on class A after merging. - assertEquals(3, aClassSubject.allMethods().size()); - } + // There should be three constructors on class A after merging. + assertEquals(3, aClassSubject.allMethods().size()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergeNonFinalAndFinalClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergeNonFinalAndFinalClassTest.java index c8a36b6..1285ea1 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergeNonFinalAndFinalClassTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergeNonFinalAndFinalClassTest.java
@@ -5,7 +5,7 @@ package com.android.tools.r8.classmerging.horizontal; import static com.android.tools.r8.utils.codeinspector.Matchers.isFinal; -import static com.android.tools.r8.utils.codeinspector.Matchers.notIf; +import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import com.android.tools.r8.NeverClassInline; @@ -14,9 +14,8 @@ import org.junit.Test; public class MergeNonFinalAndFinalClassTest extends HorizontalClassMergingTestBase { - public MergeNonFinalAndFinalClassTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public MergeNonFinalAndFinalClassTest(TestParameters parameters) { + super(parameters); } @Test @@ -24,19 +23,13 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) .compile() - .inspect( - inspector -> - assertThat( - inspector.clazz(A.class), notIf(isFinal(), enableHorizontalClassMerging))) + .inspect(inspector -> assertThat(inspector.clazz(A.class), not(isFinal()))) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("a", "b", "b", "c"); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergePackagePrivateWithPublicClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergePackagePrivateWithPublicClassTest.java index 04d69b1d..409ea48 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergePackagePrivateWithPublicClassTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergePackagePrivateWithPublicClassTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.TestParameters; @@ -14,9 +14,8 @@ public class MergePackagePrivateWithPublicClassTest extends HorizontalClassMergingTestBase { - public MergePackagePrivateWithPublicClassTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public MergePackagePrivateWithPublicClassTest(TestParameters parameters) { + super(parameters); } @Test @@ -26,9 +25,6 @@ .addProgramClasses( PackagePrivateClassRunner.class, PackagePrivateClassRunner.getPrivateClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -39,8 +35,7 @@ codeInspector -> { assertThat(codeInspector.clazz(PackagePrivateClassRunner.class), isPresent()); assertThat( - codeInspector.clazz(PackagePrivateClassRunner.getPrivateClass()), - notIf(isPresent(), enableHorizontalClassMerging)); + codeInspector.clazz(PackagePrivateClassRunner.getPrivateClass()), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java index f913560..5484fd8 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java
@@ -21,9 +21,8 @@ public class MergedConstructorForwardingTest extends HorizontalClassMergingTestBase { - public MergedConstructorForwardingTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public MergedConstructorForwardingTest(TestParameters parameters) { + super(parameters); } @Test @@ -31,9 +30,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -41,7 +37,6 @@ .assertSuccessWithOutputLines("42", "13", "21", "39", "print a", "print b") .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { ClassSubject aClassSubject = codeInspector.clazz(A.class); assertThat(aClassSubject, isPresent()); FieldSubject classIdFieldSubject = @@ -63,12 +58,6 @@ assertThat(printSubject, readsInstanceField(classIdFieldSubject.getDexField())); assertThat(codeInspector.clazz(B.class), not(isPresent())); - - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java index a11a7d6..e785238 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
@@ -22,9 +22,8 @@ public StackTrace expectedStackTrace; - public MergedConstructorStackTraceTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public MergedConstructorStackTraceTest(TestParameters parameters) { + super(parameters); } @Before @@ -45,9 +44,6 @@ .addKeepMainRule(Main.class) .addKeepAttributeLineNumberTable() .addKeepAttributeSourceFile() - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNoVerticalClassMergingAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -56,7 +52,6 @@ .inspectStackTrace( (stackTrace, codeInspector) -> { assertThat(codeInspector.clazz(A.class), isPresent()); - if (enableHorizontalClassMerging) { StackTrace expectedStackTraceWithMergedConstructor = StackTrace.builder() .add(expectedStackTrace) @@ -73,10 +68,6 @@ .build(); assertThat(stackTrace, isSame(expectedStackTraceWithMergedConstructor)); assertThat(codeInspector.clazz(B.class), not(isPresent())); - } else { - assertThat(stackTrace, isSame(expectedStackTrace)); - assertThat(codeInspector.clazz(B.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java index 8c9d11d..0375885 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java
@@ -5,8 +5,8 @@ package com.android.tools.r8.classmerging.horizontal; import static com.android.tools.r8.naming.retrace.StackTrace.isSame; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -19,9 +19,8 @@ import org.junit.Test; public class MergedVirtualMethodStackTraceTest extends HorizontalClassMergingTestBase { - public MergedVirtualMethodStackTraceTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public MergedVirtualMethodStackTraceTest(TestParameters parameters) { + super(parameters); } public StackTrace expectedStackTrace; @@ -45,38 +44,30 @@ .addKeepAttributeLineNumberTable() .addKeepAttributeSourceFile() .addDontWarn(C.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> inspector.assertMergedInto(Program.B.class, Program.A.class)) .run(parameters.getRuntime(), Program.Main.class) .inspectStackTrace( (stackTrace, codeInspector) -> { assertThat(codeInspector.clazz(Program.A.class), isPresent()); - assertThat( - codeInspector.clazz(Program.B.class), - notIf(isPresent(), enableHorizontalClassMerging)); - if (enableHorizontalClassMerging) { - StackTrace expectedStackTraceWithMergedMethod = - StackTrace.builder() - .add(expectedStackTrace) - .add( - 1, - StackTraceLine.builder() - .setClassName(Program.A.class.getTypeName()) - .setMethodName("foo$bridge") - .setFileName("Program.java") - .setFileName(getClass().getSimpleName() + ".java") - .setLineNumber(stackTrace.get(1).lineNumber) - .build()) - .build(); - assertThat(stackTrace, isSame(expectedStackTraceWithMergedMethod)); - } + assertThat(codeInspector.clazz(Program.B.class), isAbsent()); + StackTrace expectedStackTraceWithMergedMethod = + StackTrace.builder() + .add(expectedStackTrace) + .add( + 1, + StackTraceLine.builder() + .setClassName(Program.A.class.getTypeName()) + .setMethodName("foo$bridge") + .setFileName("Program.java") + .setFileName(getClass().getSimpleName() + ".java") + .setLineNumber(stackTrace.get(1).lineNumber) + .build()) + .build(); + assertThat(stackTrace, isSame(expectedStackTraceWithMergedMethod)); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStaticizerTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStaticizerTest.java index e7eda20..3ffb5a2 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStaticizerTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStaticizerTest.java
@@ -10,9 +10,8 @@ import org.junit.Test; public class MergedVirtualMethodStaticizerTest extends HorizontalClassMergingTestBase { - public MergedVirtualMethodStaticizerTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public MergedVirtualMethodStaticizerTest(TestParameters parameters) { + super(parameters); } @Test @@ -20,14 +19,10 @@ testForR8(parameters.getBackend()) .addInnerClasses(Program.class) .addKeepClassAndMembersRules(Program.Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> inspector.assertMergedInto(Program.B.class, Program.A.class)) .run(parameters.getRuntime(), Program.Main.class) .assertSuccessWithOutputLines("A::foo", "Staticized::foo", "B::foo");
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergingProducesFieldCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergingProducesFieldCollisionTest.java index 13cc54f..06242c1 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergingProducesFieldCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergingProducesFieldCollisionTest.java
@@ -4,22 +4,20 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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 static org.junit.Assert.assertEquals; import com.android.tools.r8.NeverClassInline; import com.android.tools.r8.NeverInline; -import com.android.tools.r8.NoVerticalClassMerging; import com.android.tools.r8.TestParameters; import com.android.tools.r8.utils.codeinspector.ClassSubject; import org.junit.Test; public class MergingProducesFieldCollisionTest extends HorizontalClassMergingTestBase { - public MergingProducesFieldCollisionTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public MergingProducesFieldCollisionTest(TestParameters parameters) { + super(parameters); } @Test @@ -30,9 +28,6 @@ .addKeepMainRule(Main.class) .addProgramClassFileData(transformedC) .addProgramClasses(Parent.class, A.class, B.class, Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -46,16 +41,13 @@ assertThat(aClassSubject, isPresent()); ClassSubject bClassSubject = codeInspector.clazz(B.class); - assertThat(bClassSubject, notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(bClassSubject, isAbsent()); ClassSubject cClassSubject = codeInspector.clazz(C.class); assertThat(cClassSubject, isPresent()); - if (enableHorizontalClassMerging) { - assertEquals( - cClassSubject.allFields().get(0).type(), - cClassSubject.allFields().get(1).type()); - } + assertEquals( + cClassSubject.allFields().get(0).type(), cClassSubject.allFields().get(1).type()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MinimizeFieldCastsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MinimizeFieldCastsTest.java index 90ae326..319e1c0 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MinimizeFieldCastsTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MinimizeFieldCastsTest.java
@@ -12,8 +12,8 @@ public class MinimizeFieldCastsTest extends HorizontalClassMergingTestBase { - public MinimizeFieldCastsTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public MinimizeFieldCastsTest(TestParameters parameters) { + super(parameters); } @Test @@ -21,15 +21,11 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> // Two merge groups are expected since we attempt to merge classes in a way that // avoids merging fields with different types unless strictly required for merging.
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java index a043e68..215ce7a 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java
@@ -4,24 +4,23 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static com.android.tools.r8.utils.codeinspector.Matchers.isPrivate; import static com.android.tools.r8.utils.codeinspector.Matchers.isStatic; -import static com.android.tools.r8.utils.codeinspector.Matchers.notIf; import static org.hamcrest.MatcherAssert.assertThat; import com.android.tools.r8.Jdk9TestUtils; import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.TestRuntime.CfVm; import com.android.tools.r8.classmerging.horizontal.NestClassTest.R.horizontalclassmerging.BasicNestHostHorizontalClassMerging; import com.android.tools.r8.classmerging.horizontal.NestClassTest.R.horizontalclassmerging.BasicNestHostHorizontalClassMerging2; -import com.android.tools.r8.utils.BooleanUtils; import com.android.tools.r8.utils.ReflectiveBuildPathUtils.ExamplesClass; import com.android.tools.r8.utils.ReflectiveBuildPathUtils.ExamplesJava11RootPackage; import com.android.tools.r8.utils.ReflectiveBuildPathUtils.ExamplesPackage; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.MethodSubject; -import java.util.List; import org.junit.Test; import org.junit.runners.Parameterized; @@ -42,15 +41,13 @@ } } - public NestClassTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public NestClassTest(TestParameters parameters) { + super(parameters); } - @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") - public static List<Object[]> data() { - return buildParameters( - getTestParameters().withCfRuntimesStartingFromIncluding(CfVm.JDK11).build(), - BooleanUtils.values()); + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withCfRuntimesStartingFromIncluding(CfVm.JDK11).build(); } @Test @@ -59,9 +56,6 @@ .addKeepMainRule(examplesTypeName(BasicNestHostHorizontalClassMerging.class)) .addExamplesProgramFiles(R.class) .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp)) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .compile() @@ -98,11 +92,11 @@ assertThat( codeInspector.clazz( examplesTypeName(BasicNestHostHorizontalClassMerging.B.class)), - notIf(isPresent(), enableHorizontalClassMerging)); + isAbsent()); assertThat( codeInspector.clazz( examplesTypeName(BasicNestHostHorizontalClassMerging2.B.class)), - notIf(isPresent(), enableHorizontalClassMerging)); + isAbsent()); // TODO(b/165517236): Explicitly check 1.B is merged into 1.A, and 2.B into 2.A. });
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAbstractClassesWithNonAbstractClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAbstractClassesWithNonAbstractClassesTest.java index 5566f45..4ebbd51 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAbstractClassesWithNonAbstractClassesTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAbstractClassesWithNonAbstractClassesTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -15,9 +15,8 @@ import org.junit.Test; public class NoAbstractClassesWithNonAbstractClassesTest extends HorizontalClassMergingTestBase { - public NoAbstractClassesWithNonAbstractClassesTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public NoAbstractClassesWithNonAbstractClassesTest(TestParameters parameters) { + super(parameters); } @Test @@ -25,9 +24,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() @@ -39,8 +35,7 @@ assertThat(codeInspector.clazz(A.class), isPresent()); assertThat(codeInspector.clazz(B.class), isPresent()); assertThat(codeInspector.clazz(C.class), isPresent()); - assertThat( - codeInspector.clazz(D.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(D.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoClassesOrMembersWithAnnotationsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoClassesOrMembersWithAnnotationsTest.java index 441934e..385a3fe 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoClassesOrMembersWithAnnotationsTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoClassesOrMembersWithAnnotationsTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -20,9 +20,9 @@ import org.junit.Test; public class NoClassesOrMembersWithAnnotationsTest extends HorizontalClassMergingTestBase { - public NoClassesOrMembersWithAnnotationsTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + + public NoClassesOrMembersWithAnnotationsTest(TestParameters parameters) { + super(parameters); } @Test @@ -31,11 +31,7 @@ .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> inspector.assertIsCompleteMergeGroup(A.class, C.class)) .enableNeverClassInliningAnnotations() .enableInliningAnnotations() @@ -49,8 +45,7 @@ assertThat(codeInspector.clazz(MethodAnnotation.class), isPresent()); assertThat(codeInspector.clazz(A.class), isPresent()); assertThat(codeInspector.clazz(B.class), isPresent()); - assertThat( - codeInspector.clazz(C.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(C.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoHorizontalClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoHorizontalClassMergingTest.java index 5c0e207..1382648 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoHorizontalClassMergingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoHorizontalClassMergingTest.java
@@ -13,9 +13,8 @@ import org.junit.Test; public class NoHorizontalClassMergingTest extends HorizontalClassMergingTestBase { - public NoHorizontalClassMergingTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public NoHorizontalClassMergingTest(TestParameters parameters) { + super(parameters); } @Test @@ -23,9 +22,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNoHorizontalClassMergingAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -33,13 +29,8 @@ .assertSuccessWithOutputLines("a", "b") .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { assertThat(codeInspector.clazz(A.class), isPresent()); assertThat(codeInspector.clazz(B.class), isPresent()); - } else { - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonFinalOverrideOfFinalMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonFinalOverrideOfFinalMethodTest.java index d73ffcf..110f7f6 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonFinalOverrideOfFinalMethodTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonFinalOverrideOfFinalMethodTest.java
@@ -12,24 +12,21 @@ import com.android.tools.r8.NeverInline; import com.android.tools.r8.NoVerticalClassMerging; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.utils.BooleanUtils; +import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.MethodSubject; -import java.util.List; import org.junit.Test; import org.junit.runners.Parameterized; public class NonFinalOverrideOfFinalMethodTest extends HorizontalClassMergingTestBase { - @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") - public static List<Object[]> data() { - return buildParameters( - getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.trueValues()); + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); } - public NonFinalOverrideOfFinalMethodTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public NonFinalOverrideOfFinalMethodTest(TestParameters parameters) { + super(parameters); } @Test @@ -37,15 +34,12 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .compile() .inspect( inspector -> {
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessOnMergedClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessOnMergedClassTest.java index 029035e..a54102f 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessOnMergedClassTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessOnMergedClassTest.java
@@ -14,9 +14,8 @@ @RunWith(Parameterized.class) public class NonReboundFieldAccessOnMergedClassTest extends HorizontalClassMergingTestBase { - public NonReboundFieldAccessOnMergedClassTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public NonReboundFieldAccessOnMergedClassTest(TestParameters parameters) { + super(parameters); } @Test @@ -25,11 +24,8 @@ .addInnerClasses(getClass()) .addInnerClasses(NonReboundFieldAccessOnMergedClassTestClasses.class) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(D.class, C.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(D.class, C.class)) .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessWithMergedTypeTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessWithMergedTypeTest.java index 03b99e0..4b17a09 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessWithMergedTypeTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessWithMergedTypeTest.java
@@ -14,9 +14,8 @@ @RunWith(Parameterized.class) public class NonReboundFieldAccessWithMergedTypeTest extends HorizontalClassMergingTestBase { - public NonReboundFieldAccessWithMergedTypeTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public NonReboundFieldAccessWithMergedTypeTest(TestParameters parameters) { + super(parameters); } @Test @@ -25,11 +24,7 @@ .addInnerClasses(getClass()) .addInnerClasses(NonReboundFieldAccessWithMergedTypeTestClasses.class) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> inspector.assertMergedInto(WorldGreeting.class, HelloGreeting.class)) .enableNeverClassInliningAnnotations() .enableNoHorizontalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/OverlappingConstructorsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/OverlappingConstructorsTest.java index c97e384..2927247 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/OverlappingConstructorsTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/OverlappingConstructorsTest.java
@@ -14,9 +14,8 @@ public class OverlappingConstructorsTest extends HorizontalClassMergingTestBase { - public OverlappingConstructorsTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public OverlappingConstructorsTest(TestParameters parameters) { + super(parameters); } @Test @@ -24,24 +23,14 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class) .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { assertThat(codeInspector.clazz(A.class), isPresent()); assertThat(codeInspector.clazz(B.class), not(isPresent())); assertThat(codeInspector.clazz(C.class), not(isPresent())); - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - assertThat(codeInspector.clazz(C.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java index 2732240..820af37 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java
@@ -15,9 +15,8 @@ import org.junit.Test; public class PackagePrivateMemberAccessTest extends HorizontalClassMergingTestBase { - public PackagePrivateMemberAccessTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public PackagePrivateMemberAccessTest(TestParameters parameters) { + super(parameters); } @Test @@ -27,9 +26,6 @@ .addProgramClasses(A.class) .addProgramClasses(B.class) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .allowAccessModification(false) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() @@ -38,16 +34,9 @@ .assertSuccessWithOutputLines("foo", "B", "bar", "5", "foobar") .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { assertThat(codeInspector.clazz(A.class), isPresent()); assertThat(codeInspector.clazz(B.class), not(isPresent())); assertThat(codeInspector.clazz(C.class), isPresent()); - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - assertThat(codeInspector.clazz(C.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java index 4d7c0c4..bb756d0 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java
@@ -14,9 +14,8 @@ import org.junit.Test; public class PackagePrivateMembersAccessedTest extends HorizontalClassMergingTestBase { - public PackagePrivateMembersAccessedTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public PackagePrivateMembersAccessedTest(TestParameters parameters) { + super(parameters); } @Test @@ -26,9 +25,6 @@ .addProgramClasses(C.class) .addProgramClasses(D.class) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .allowAccessModification(false) .enableInliningAnnotations() .enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberReferenceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberReferenceTest.java index 2f01f90..41694f6 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberReferenceTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberReferenceTest.java
@@ -18,18 +18,14 @@ import org.junit.Test; public class PinnedClassMemberReferenceTest extends HorizontalClassMergingTestBase { - public PinnedClassMemberReferenceTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public PinnedClassMemberReferenceTest(TestParameters parameters) { + super(parameters); } private R8FullTestBuilder testCommon() throws Exception { return testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .noMinification() .enableInliningAnnotations() .enableNeverClassInliningAnnotations() @@ -46,7 +42,6 @@ @Test public void testWithoutKeepRules() throws Exception { // This is just a small check ensure that without the keep rules the classes are merged. - assumeTrue(enableHorizontalClassMerging); assumeTrue(parameters.isCfRuntime()); runAndAssertOutput(testCommon())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberTest.java index 1e09a5a..ca080ae 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberTest.java
@@ -12,8 +12,8 @@ import org.junit.Test; public class PinnedClassMemberTest extends HorizontalClassMergingTestBase { - public PinnedClassMemberTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public PinnedClassMemberTest(TestParameters parameters) { + super(parameters); } @Test @@ -22,9 +22,6 @@ .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .addKeepRules("-keepclassmembers class " + B.class.getTypeName() + " { void foo(); }") - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassTest.java index 0ba06e6..af092cc 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassTest.java
@@ -12,8 +12,8 @@ import org.junit.Test; public class PinnedClassTest extends HorizontalClassMergingTestBase { - public PinnedClassTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public PinnedClassTest(TestParameters parameters) { + super(parameters); } @Test @@ -22,9 +22,6 @@ .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .addKeepClassRules(B.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexListTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexListTest.java index e3e1b85..2aeacb8 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexListTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexListTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsNot.not; @@ -12,48 +13,46 @@ import com.android.tools.r8.OutputMode; import com.android.tools.r8.R8TestCompileResult; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.classmerging.horizontal.EmptyClassTest.A; -import com.android.tools.r8.classmerging.horizontal.EmptyClassTest.B; -import com.android.tools.r8.classmerging.horizontal.EmptyClassTest.Main; -import com.android.tools.r8.utils.BooleanUtils; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.errors.UnsupportedMainDexListUsageDiagnostic; import com.android.tools.r8.utils.codeinspector.CodeInspector; import java.nio.file.Path; -import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(Parameterized.class) public class PreventMergeMainDexListTest extends HorizontalClassMergingTestBase { - public PreventMergeMainDexListTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public PreventMergeMainDexListTest(TestParameters parameters) { + super(parameters); } - @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") - public static List<Object[]> data() { - return buildParameters( - getTestParameters() - .withDexRuntimes() - .withApiLevelsEndingAtExcluding(apiLevelWithNativeMultiDexSupport()) - .build(), - BooleanUtils.values()); + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters() + .withDexRuntimes() + .withApiLevelsEndingAtExcluding(apiLevelWithNativeMultiDexSupport()) + .build(); } + // TODO(b/181858113): This test is likely obsolete once main-dex-list support is removed. + // Ensure the main-dex-rules variant of this test (PreventMergeMainDexTracingTest) is sufficient. @Test public void testR8() throws Exception { testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepClassAndMembersRules(Main.class) .addMainDexListClasses(A.class, Main.class) - .addOptionsModification( - options -> { - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging); - options.minimalMainDex = true; - }) + .addOptionsModification(options -> options.minimalMainDex = true) .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .compile() + .allowDiagnosticMessages() + .compileWithExpectedDiagnostics( + diagnostics -> + diagnostics + .assertOnlyWarnings() + .assertWarningsMatch( + diagnosticType(UnsupportedMainDexListUsageDiagnostic.class))) .apply(this::checkCompileResult) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("main dex");
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexTracingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexTracingTest.java index 13d8a62..de0bd57 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexTracingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexTracingTest.java
@@ -13,29 +13,25 @@ import com.android.tools.r8.OutputMode; import com.android.tools.r8.R8TestCompileResult; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.utils.BooleanUtils; +import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.utils.codeinspector.CodeInspector; import java.nio.file.Path; -import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(Parameterized.class) public class PreventMergeMainDexTracingTest extends HorizontalClassMergingTestBase { - public PreventMergeMainDexTracingTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public PreventMergeMainDexTracingTest(TestParameters parameters) { + super(parameters); } - @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") - public static List<Object[]> data() { - return buildParameters( - getTestParameters() - .withDexRuntimes() - .withApiLevelsEndingAtExcluding(apiLevelWithNativeMultiDexSupport()) - .build(), - BooleanUtils.values()); + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters() + .withDexRuntimes() + .withApiLevelsEndingAtExcluding(apiLevelWithNativeMultiDexSupport()) + .build(); } @Test @@ -44,12 +40,8 @@ .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .addKeepClassAndMembersRules(Other.class) - .addMainDexClassRules(Main.class) - .addOptionsModification( - options -> { - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging); - options.minimalMainDex = true; - }) + .addMainDexKeepClassRules(Main.class) + .addOptionsModification(options -> options.minimalMainDex = true) .enableNeverClassInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndInterfaceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndInterfaceMethodCollisionTest.java index 4553469..f440689 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndInterfaceMethodCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndInterfaceMethodCollisionTest.java
@@ -14,9 +14,8 @@ public class PrivateAndInterfaceMethodCollisionTest extends HorizontalClassMergingTestBase { - public PrivateAndInterfaceMethodCollisionTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public PrivateAndInterfaceMethodCollisionTest(TestParameters parameters) { + super(parameters); } @Test @@ -24,9 +23,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .addHorizontallyMergedClassesInspector( HorizontallyMergedClassesInspector::assertNoClassesMerged) .enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndStaticMethodCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndStaticMethodCollisionTest.java index 3c7b799..a646bf3 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndStaticMethodCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndStaticMethodCollisionTest.java
@@ -11,9 +11,8 @@ public class PrivateAndStaticMethodCollisionTest extends HorizontalClassMergingTestBase { - public PrivateAndStaticMethodCollisionTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public PrivateAndStaticMethodCollisionTest(TestParameters parameters) { + super(parameters); } @Test @@ -21,11 +20,8 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ReferencedInAnnotationTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ReferencedInAnnotationTest.java index 385d782..08f1f0d 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ReferencedInAnnotationTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ReferencedInAnnotationTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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 static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -26,9 +26,8 @@ public class ReferencedInAnnotationTest extends HorizontalClassMergingTestBase { - public ReferencedInAnnotationTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ReferencedInAnnotationTest(TestParameters parameters) { + super(parameters); } @Test @@ -37,9 +36,6 @@ .addInnerClasses(getClass()) .addKeepMainRule(TestClass.class) .addKeepClassAndMembersRules(Annotation.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .addKeepRuntimeVisibleAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -58,7 +54,7 @@ // B should have been merged into A if horizontal class merging is enabled. ClassSubject bClassSubject = inspector.clazz(B.class); - assertThat(bClassSubject, notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(bClassSubject, isAbsent()); // The annotation on TestClass should now refer to A instead of B. AnnotationSubject annotationSubject = @@ -72,11 +68,7 @@ assertTrue(annotationElementValue.isDexValueType()); DexType annotationElementValueType = annotationElementValue.asDexValueType().getValue(); - assertEquals( - (enableHorizontalClassMerging ? aClassSubject : bClassSubject) - .getDexProgramClass() - .getType(), - annotationElementValueType); + assertEquals(aClassSubject.getDexProgramClass().getType(), annotationElementValueType); } @Annotation(B.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapFieldTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapFieldTest.java index 168d6ee..3abb15d 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapFieldTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapFieldTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -14,8 +14,8 @@ import org.junit.Test; public class RemapFieldTest extends HorizontalClassMergingTestBase { - public RemapFieldTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public RemapFieldTest(TestParameters parameters) { + super(parameters); } @Test @@ -23,14 +23,10 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> inspector.assertMergedInto(B.class, A.class).assertMergedInto(D.class, C.class)) .run(parameters.getRuntime(), Main.class) @@ -38,11 +34,9 @@ .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); assertThat(codeInspector.clazz(C.class), isPresent()); - assertThat( - codeInspector.clazz(D.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(D.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapMethodTest.java index c640ffc..71e3e74 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapMethodTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapMethodTest.java
@@ -14,8 +14,8 @@ import org.junit.Test; public class RemapMethodTest extends HorizontalClassMergingTestBase { - public RemapMethodTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public RemapMethodTest(TestParameters parameters) { + super(parameters); } @Test @@ -23,9 +23,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -36,14 +33,8 @@ codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); assertThat(codeInspector.clazz(C.class), isPresent()); - if (enableHorizontalClassMerging) { assertThat(codeInspector.clazz(B.class), not(isPresent())); assertThat(codeInspector.clazz(D.class), not(isPresent())); - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(B.class), isPresent()); - assertThat(codeInspector.clazz(D.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderParentTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderParentTest.java index 5eab9c9..311d835 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderParentTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderParentTest.java
@@ -18,8 +18,8 @@ import org.junit.Test; public class ServiceLoaderParentTest extends HorizontalClassMergingTestBase { - public ServiceLoaderParentTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ServiceLoaderParentTest(TestParameters parameters) { + super(parameters); } @Test @@ -37,9 +37,6 @@ "META-INF/services/" + A.class.getTypeName(), Origin.unknown())) .enableNoVerticalClassMergingAnnotations() - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class) .assertSuccess()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderTest.java index f9ae4bd..0b4a848 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderTest.java
@@ -17,8 +17,8 @@ import org.junit.Test; public class ServiceLoaderTest extends HorizontalClassMergingTestBase { - public ServiceLoaderTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public ServiceLoaderTest(TestParameters parameters) { + super(parameters); } @Test @@ -35,9 +35,6 @@ StringUtils.lines(serviceImplementations).getBytes(), "META-INF/services/" + A.class.getTypeName(), Origin.unknown())) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class) .assertSuccess()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndInterfaceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndInterfaceMethodCollisionTest.java index e76dd447..48844ff 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndInterfaceMethodCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndInterfaceMethodCollisionTest.java
@@ -14,9 +14,8 @@ public class StaticAndInterfaceMethodCollisionTest extends HorizontalClassMergingTestBase { - public StaticAndInterfaceMethodCollisionTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public StaticAndInterfaceMethodCollisionTest(TestParameters parameters) { + super(parameters); } @Test @@ -24,9 +23,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .addHorizontallyMergedClassesInspector( HorizontallyMergedClassesInspector::assertNoClassesMerged) .enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndVirtualMethodCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndVirtualMethodCollisionTest.java index 35a15e5..993dd65 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndVirtualMethodCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndVirtualMethodCollisionTest.java
@@ -12,9 +12,8 @@ public class StaticAndVirtualMethodCollisionTest extends HorizontalClassMergingTestBase { - public StaticAndVirtualMethodCollisionTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public StaticAndVirtualMethodCollisionTest(TestParameters parameters) { + super(parameters); } @Test @@ -22,11 +21,8 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class)) + .addHorizontallyMergedClassesInspector( + inspector -> inspector.assertMergedInto(B.class, A.class)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/StrictMethodMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/StrictMethodMergingTest.java index 762824f..4d793a4 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/StrictMethodMergingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/StrictMethodMergingTest.java
@@ -12,23 +12,21 @@ import com.android.tools.r8.NeverClassInline; import com.android.tools.r8.NeverInline; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.utils.BooleanUtils; +import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.MethodSubject; -import java.util.List; import org.junit.Test; import org.junit.runners.Parameterized; public class StrictMethodMergingTest extends HorizontalClassMergingTestBase { - @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") - public static List<Object[]> data() { - return buildParameters( - getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.trueValues()); + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); } - public StrictMethodMergingTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public StrictMethodMergingTest(TestParameters parameters) { + super(parameters); } @Test @@ -36,14 +34,10 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> inspector.assertMergedInto(B.class, A.class).assertMergedInto(D.class, C.class)) .compile()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java index ecbd84b..821d644 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java
@@ -14,9 +14,8 @@ import org.junit.Test; public class SuperConstructorCallsVirtualMethodTest extends HorizontalClassMergingTestBase { - public SuperConstructorCallsVirtualMethodTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public SuperConstructorCallsVirtualMethodTest(TestParameters parameters) { + super(parameters); } @Test @@ -24,9 +23,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -34,16 +30,9 @@ .assertSuccessWithOutputLines("5", "foo hello", "B", "bar world", "5", "B") .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { assertThat(codeInspector.clazz(Parent.class), isPresent()); assertThat(codeInspector.clazz(A.class), isPresent()); assertThat(codeInspector.clazz(B.class), not(isPresent())); - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(Parent.class), isPresent()); - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/SynchronizedClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/SynchronizedClassesTest.java index 6f458b7..a88c32b 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/SynchronizedClassesTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/SynchronizedClassesTest.java
@@ -15,8 +15,8 @@ import org.junit.Test; public class SynchronizedClassesTest extends HorizontalClassMergingTestBase { - public SynchronizedClassesTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public SynchronizedClassesTest(TestParameters parameters) { + super(parameters); } @Test @@ -24,10 +24,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> { - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging); - }) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -38,7 +34,6 @@ codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); assertThat(codeInspector.clazz(B.class), isPresent()); - if (enableHorizontalClassMerging) { // C has been merged into A. assertThat(codeInspector.clazz(C.class), not(isPresent())); assertThat(codeInspector.clazz(A.class).init("long"), isPresent()); @@ -47,10 +42,6 @@ assertThat(codeInspector.clazz(D.class), not(isPresent())); ClassSubject bClassSubject = codeInspector.clazz(B.class); assertThat(bClassSubject.init("boolean"), isPresent()); - } else { - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/SynchronizedMethodMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/SynchronizedMethodMergingTest.java index 8d802c4..4811a41 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/SynchronizedMethodMergingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/SynchronizedMethodMergingTest.java
@@ -12,24 +12,21 @@ import com.android.tools.r8.NeverClassInline; import com.android.tools.r8.NeverInline; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.utils.BooleanUtils; +import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.MethodSubject; -import java.util.List; import org.junit.Test; import org.junit.runners.Parameterized; public class SynchronizedMethodMergingTest extends HorizontalClassMergingTestBase { - @Parameterized.Parameters(name = "{0}, horizontalClassMerging:{1}") - public static List<Object[]> data() { - return buildParameters( - getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.trueValues()); + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); } - public SynchronizedMethodMergingTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public SynchronizedMethodMergingTest(TestParameters parameters) { + super(parameters); } @Test @@ -37,14 +34,10 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, + .addHorizontallyMergedClassesInspector( inspector -> inspector.assertMergedInto(B.class, A.class).assertMergedInto(D.class, C.class)) .compile()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/SyntheticConstructorArgumentsMerged.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/SyntheticConstructorArgumentsMerged.java index 6567764..eb3fe19 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/SyntheticConstructorArgumentsMerged.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/SyntheticConstructorArgumentsMerged.java
@@ -14,9 +14,8 @@ import org.junit.Test; public class SyntheticConstructorArgumentsMerged extends HorizontalClassMergingTestBase { - public SyntheticConstructorArgumentsMerged( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public SyntheticConstructorArgumentsMerged(TestParameters parameters) { + super(parameters); } @Test @@ -24,10 +23,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> { - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging); - }) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -36,14 +31,8 @@ .assertSuccessWithOutputLines("5", "42") .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { assertThat(codeInspector.clazz(A.class), isPresent()); assertThat(codeInspector.clazz(B.class), not(isPresent())); - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerCollisionTest.java index 97e41db..2b56278 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerCollisionTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -16,8 +16,8 @@ import org.junit.Test; public class TreeFixerCollisionTest extends HorizontalClassMergingTestBase { - public TreeFixerCollisionTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public TreeFixerCollisionTest(TestParameters parameters) { + super(parameters); } @Test @@ -25,9 +25,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() @@ -39,13 +36,11 @@ .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); assertThat(codeInspector.clazz(Group2.class), isPresent()); assertThat(codeInspector.clazz(C.class), isPresent()); assertThat(codeInspector.clazz(D.class), isPresent()); - assertThat( - codeInspector.clazz(E.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(E.class), isAbsent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerConstructorCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerConstructorCollisionTest.java index 5239543..c5dff9d 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerConstructorCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerConstructorCollisionTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -15,9 +15,8 @@ import org.junit.Test; public class TreeFixerConstructorCollisionTest extends HorizontalClassMergingTestBase { - public TreeFixerConstructorCollisionTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public TreeFixerConstructorCollisionTest(TestParameters parameters) { + super(parameters); } @Test @@ -25,9 +24,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() @@ -43,8 +39,7 @@ .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); assertThat(codeInspector.clazz(C.class), isPresent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceCollisionTest.java index dbc83c8..fb7e05e 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceCollisionTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -22,9 +22,8 @@ * changed. */ public class TreeFixerInterfaceCollisionTest extends HorizontalClassMergingTestBase { - public TreeFixerInterfaceCollisionTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public TreeFixerInterfaceCollisionTest(TestParameters parameters) { + super(parameters); } @Test @@ -33,9 +32,6 @@ .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .noMinification() - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() @@ -46,15 +42,12 @@ .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); ClassSubject parentClassSubject = codeInspector.clazz(Parent.class); assertThat(parentClassSubject, isPresent()); - if (enableHorizontalClassMerging) { - // Parent#foo is renamed to Parent#foo1 to prevent collision. - assertThat(parentClassSubject.uniqueMethodWithName("foo$1"), isPresent()); - } + // Parent#foo is renamed to Parent#foo1 to prevent collision. + assertThat(parentClassSubject.uniqueMethodWithName("foo$1"), isPresent()); ClassSubject cClassSubject = codeInspector.clazz(C.class); assertThat(cClassSubject, isPresent());
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceFixedCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceFixedCollisionTest.java index 169a59b..4dfb6df 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceFixedCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceFixedCollisionTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -22,9 +22,8 @@ * changed. */ public class TreeFixerInterfaceFixedCollisionTest extends HorizontalClassMergingTestBase { - public TreeFixerInterfaceFixedCollisionTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public TreeFixerInterfaceFixedCollisionTest(TestParameters parameters) { + super(parameters); } @Test @@ -33,9 +32,6 @@ .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .noMinification() - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() @@ -46,15 +42,12 @@ .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); ClassSubject parentClassSubject = codeInspector.clazz(Parent.class); assertThat(parentClassSubject, isPresent()); - if (enableHorizontalClassMerging) { - // Parent#foo is renamed to Parent#foo1 to prevent collision. - assertThat(parentClassSubject.uniqueMethodWithFinalName("foo$1"), isPresent()); - } + // Parent#foo is renamed to Parent#foo1 to prevent collision. + assertThat(parentClassSubject.uniqueMethodWithFinalName("foo$1"), isPresent()); ClassSubject cClassSubject = codeInspector.clazz(C.class); assertThat(cClassSubject, isPresent());
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceImplementedByParentTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceImplementedByParentTest.java index afee32c..65b57aa 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceImplementedByParentTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceImplementedByParentTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -22,9 +22,8 @@ * changed. */ public class TreeFixerInterfaceImplementedByParentTest extends HorizontalClassMergingTestBase { - public TreeFixerInterfaceImplementedByParentTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public TreeFixerInterfaceImplementedByParentTest(TestParameters parameters) { + super(parameters); } @Test @@ -33,9 +32,6 @@ .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .noMinification() - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() @@ -46,17 +42,14 @@ .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); ClassSubject parentClassSubject = codeInspector.clazz(Parent.class); assertThat(parentClassSubject, isPresent()); // Parent #foo(A) is kept as is. - if (enableHorizontalClassMerging) { - // Parent#foo(B) is renamed to Parent#foo1 to prevent collision. - assertThat(parentClassSubject.uniqueMethodWithFinalName("foo"), isPresent()); - assertThat(parentClassSubject.uniqueMethodWithFinalName("foo$1"), isPresent()); - } + // Parent#foo(B) is renamed to Parent#foo1 to prevent collision. + assertThat(parentClassSubject.uniqueMethodWithFinalName("foo"), isPresent()); + assertThat(parentClassSubject.uniqueMethodWithFinalName("foo$1"), isPresent()); assertThat(codeInspector.clazz(C.class), isPresent());
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerSubClassCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerSubClassCollisionTest.java index b68f291..5e8b88d 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerSubClassCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerSubClassCollisionTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -17,9 +17,8 @@ import org.junit.Test; public class TreeFixerSubClassCollisionTest extends HorizontalClassMergingTestBase { - public TreeFixerSubClassCollisionTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public TreeFixerSubClassCollisionTest(TestParameters parameters) { + super(parameters); } @Test @@ -28,9 +27,6 @@ .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .noMinification() - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() @@ -42,24 +38,18 @@ .inspect( codeInspector -> { assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), isAbsent()); ClassSubject cClassSubject = codeInspector.clazz(C.class); assertThat(cClassSubject, isPresent()); // C#foo(B) is renamed to C#foo$1(A). - if (enableHorizontalClassMerging) { - assertThat(cClassSubject.uniqueMethodWithFinalName("foo"), isPresent()); - assertThat(cClassSubject.uniqueMethodWithFinalName("foo$1"), isPresent()); - } + assertThat(cClassSubject.uniqueMethodWithFinalName("foo"), isPresent()); + assertThat(cClassSubject.uniqueMethodWithFinalName("foo$1"), isPresent()); ClassSubject dClassSubject = codeInspector.clazz(D.class); assertThat(dClassSubject, isPresent()); // D#foo$1(B) is renamed to D#foo$2(A). - assertThat( - dClassSubject.uniqueMethodWithFinalName( - enableHorizontalClassMerging ? "foo$1$1" : "foo$1"), - isPresent()); + assertThat(dClassSubject.uniqueMethodWithFinalName("foo$1$1"), isPresent()); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticalMergingPreoptimizedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticalMergingPreoptimizedTest.java index b1c0b4a..db15d9c 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticalMergingPreoptimizedTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticalMergingPreoptimizedTest.java
@@ -5,7 +5,6 @@ package com.android.tools.r8.classmerging.horizontal; 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 static org.hamcrest.core.IsNot.not; @@ -17,9 +16,8 @@ public class VerticalMergingPreoptimizedTest extends HorizontalClassMergingTestBase { - public VerticalMergingPreoptimizedTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public VerticalMergingPreoptimizedTest(TestParameters parameters) { + super(parameters); } @Test @@ -27,9 +25,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() @@ -42,8 +37,7 @@ assertThat(codeInspector.clazz(Parent.class), not(isPresent())); assertThat(codeInspector.clazz(Changed.class), isPresent()); assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat( - codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(codeInspector.clazz(B.class), not(isPresent())); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByCheckCastTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByCheckCastTest.java index eba6de8..0c13090 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByCheckCastTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByCheckCastTest.java
@@ -12,9 +12,8 @@ public class VerticallyMergedClassDistinguishedByCheckCastTest extends HorizontalClassMergingTestBase { - public VerticallyMergedClassDistinguishedByCheckCastTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public VerticallyMergedClassDistinguishedByCheckCastTest(TestParameters parameters) { + super(parameters); } @Test @@ -22,9 +21,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByInstanceOfTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByInstanceOfTest.java index 47994ef..a7a9f96 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByInstanceOfTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByInstanceOfTest.java
@@ -12,9 +12,8 @@ public class VerticallyMergedClassDistinguishedByInstanceOfTest extends HorizontalClassMergingTestBase { - public VerticallyMergedClassDistinguishedByInstanceOfTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public VerticallyMergedClassDistinguishedByInstanceOfTest(TestParameters parameters) { + super(parameters); } @Test @@ -22,9 +21,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassTest.java index abd38f5..ab48235 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassTest.java
@@ -15,9 +15,8 @@ import org.junit.Test; public class VerticallyMergedClassTest extends HorizontalClassMergingTestBase { - public VerticallyMergedClassTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public VerticallyMergedClassTest(TestParameters parameters) { + super(parameters); } @Test @@ -25,9 +24,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableNoHorizontalClassMergingAnnotations() .enableInliningAnnotations() .enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfFinalAndNonFinalMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfFinalAndNonFinalMethodTest.java index 6399f3e..0c51c89 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfFinalAndNonFinalMethodTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfFinalAndNonFinalMethodTest.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.classmerging.horizontal; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; 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.NeverClassInline; @@ -17,9 +17,8 @@ public class VirtualMethodMergingOfFinalAndNonFinalMethodTest extends HorizontalClassMergingTestBase { - public VirtualMethodMergingOfFinalAndNonFinalMethodTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public VirtualMethodMergingOfFinalAndNonFinalMethodTest(TestParameters parameters) { + super(parameters); } @Test @@ -27,9 +26,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(TestClass.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() @@ -38,8 +34,7 @@ .inspect( inspector -> { assertThat(inspector.clazz(A.class), isPresent()); - assertThat( - inspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging)); + assertThat(inspector.clazz(B.class), isAbsent()); assertThat(inspector.clazz(C.class), isPresent()); }) .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfPublicizedMethodsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfPublicizedMethodsTest.java index 5e23840..d3665e0 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfPublicizedMethodsTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfPublicizedMethodsTest.java
@@ -14,9 +14,8 @@ @RunWith(Parameterized.class) public class VirtualMethodMergingOfPublicizedMethodsTest extends HorizontalClassMergingTestBase { - public VirtualMethodMergingOfPublicizedMethodsTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public VirtualMethodMergingOfPublicizedMethodsTest(TestParameters parameters) { + super(parameters); } @Test @@ -24,9 +23,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(TestClass.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .allowAccessModification() .enableInliningAnnotations() .enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/NotOverlappingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/NotOverlappingTest.java index e405aa9..3d0fe4a 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/NotOverlappingTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/NotOverlappingTest.java
@@ -13,8 +13,8 @@ import org.junit.Test; public class NotOverlappingTest extends HorizontalClassMergingTestBase { - public NotOverlappingTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public NotOverlappingTest(TestParameters parameters) { + super(parameters); } @Test @@ -22,9 +22,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -32,14 +29,8 @@ .assertSuccessWithOutputLines("foo", "bar") .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { assertThat(codeInspector.clazz(A.class), isPresent()); assertThat(codeInspector.clazz(B.class), not(isPresent())); - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java index 11164b1..3787201 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java
@@ -17,9 +17,8 @@ public class OverrideAbstractMethodWithDefaultTest extends HorizontalClassMergingTestBase { - public OverrideAbstractMethodWithDefaultTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public OverrideAbstractMethodWithDefaultTest(TestParameters parameters) { + super(parameters); } @Test @@ -27,15 +26,12 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, HorizontallyMergedClassesInspector::assertNoClassesMerged) + .addHorizontallyMergedClassesInspector( + HorizontallyMergedClassesInspector::assertNoClassesMerged) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("J", "B2") .inspect(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultMethodTest.java index 15ca564..d74ae0a 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultMethodTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultMethodTest.java
@@ -16,9 +16,8 @@ import org.junit.Test; public class OverrideDefaultMethodTest extends HorizontalClassMergingTestBase { - public OverrideDefaultMethodTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public OverrideDefaultMethodTest(TestParameters parameters) { + super(parameters); } @Test @@ -26,15 +25,12 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, HorizontallyMergedClassesInspector::assertNoClassesMerged) + .addHorizontallyMergedClassesInspector( + HorizontallyMergedClassesInspector::assertNoClassesMerged) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("I", "B", "J") .inspect(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultOnSuperMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultOnSuperMethodTest.java index 2aea3d0..95dc561 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultOnSuperMethodTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultOnSuperMethodTest.java
@@ -17,9 +17,8 @@ import org.junit.Test; public class OverrideDefaultOnSuperMethodTest extends HorizontalClassMergingTestBase { - public OverrideDefaultOnSuperMethodTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public OverrideDefaultOnSuperMethodTest(TestParameters parameters) { + super(parameters); } @Test @@ -27,16 +26,13 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoUnusedInterfaceRemovalAnnotations() .enableNoVerticalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, HorizontallyMergedClassesInspector::assertNoClassesMerged) + .addHorizontallyMergedClassesInspector( + HorizontallyMergedClassesInspector::assertNoClassesMerged) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("I", "B", "J") .inspect(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideMergeAbsentTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideMergeAbsentTest.java index 9a727f5..6f5e761 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideMergeAbsentTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideMergeAbsentTest.java
@@ -16,8 +16,8 @@ import org.junit.Test; public class OverrideMergeAbsentTest extends HorizontalClassMergingTestBase { - public OverrideMergeAbsentTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public OverrideMergeAbsentTest(TestParameters parameters) { + super(parameters); } @Test @@ -25,15 +25,12 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .addHorizontallyMergedClassesInspectorIf( - enableHorizontalClassMerging, HorizontallyMergedClassesInspector::assertNoClassesMerged) + .addHorizontallyMergedClassesInspector( + HorizontallyMergedClassesInspector::assertNoClassesMerged) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("A", "B", "A", "J") .inspect(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideParentCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideParentCollisionTest.java index 639cf19..c62f59b 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideParentCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideParentCollisionTest.java
@@ -16,9 +16,8 @@ public class OverrideParentCollisionTest extends HorizontalClassMergingTestBase { - public OverrideParentCollisionTest( - TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public OverrideParentCollisionTest(TestParameters parameters) { + super(parameters); } @Test @@ -26,9 +25,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(this.getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) @@ -36,14 +32,8 @@ .assertSuccessWithOutputLines("foo", "bar", "foo", "parent") .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { assertThat(codeInspector.clazz(A.class), isPresent()); assertThat(codeInspector.clazz(B.class), not(isPresent())); - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(A.class), isPresent()); - assertThat(codeInspector.clazz(B.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/SuperMethodMergedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/SuperMethodMergedTest.java index 44973bc..fb2189d 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/SuperMethodMergedTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/SuperMethodMergedTest.java
@@ -16,8 +16,8 @@ import org.junit.Test; public class SuperMethodMergedTest extends HorizontalClassMergingTestBase { - public SuperMethodMergedTest(TestParameters parameters, boolean enableHorizontalClassMerging) { - super(parameters, enableHorizontalClassMerging); + public SuperMethodMergedTest(TestParameters parameters) { + super(parameters); } @Test @@ -25,9 +25,6 @@ testForR8(parameters.getBackend()) .addInnerClasses(this.getClass()) .addKeepMainRule(Main.class) - .addOptionsModification( - options -> - options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() @@ -36,18 +33,10 @@ .assertSuccessWithOutputLines("foo", "parent b", "parent b", "x", "parent b") .inspect( codeInspector -> { - if (enableHorizontalClassMerging) { assertThat(codeInspector.clazz(ParentA.class), isPresent()); assertThat(codeInspector.clazz(ParentB.class), not(isPresent())); assertThat(codeInspector.clazz(X.class), isPresent()); assertThat(codeInspector.clazz(Y.class), not(isPresent())); - // TODO(b/165517236): Explicitly check classes have been merged. - } else { - assertThat(codeInspector.clazz(ParentA.class), isPresent()); - assertThat(codeInspector.clazz(ParentB.class), isPresent()); - assertThat(codeInspector.clazz(X.class), isPresent()); - assertThat(codeInspector.clazz(Y.class), isPresent()); - } }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/B141942381.java b/src/test/java/com/android/tools/r8/classmerging/vertical/B141942381.java index 97f84ef..d840b52 100644 --- a/src/test/java/com/android/tools/r8/classmerging/vertical/B141942381.java +++ b/src/test/java/com/android/tools/r8/classmerging/vertical/B141942381.java
@@ -77,8 +77,8 @@ assertThat(set, isPresent()); assertEquals( - set.getMethod().method.proto.parameters.values[0], - storage.getField().field.type.toBaseType(inspector.getFactory())); + set.getMethod().getReference().proto.parameters.values[0], + storage.getField().getReference().type.toBaseType(inspector.getFactory())); } static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/debug/ContinuousSteppingTest.java b/src/test/java/com/android/tools/r8/debug/ContinuousSteppingTest.java index beed8fc..a292274 100644 --- a/src/test/java/com/android/tools/r8/debug/ContinuousSteppingTest.java +++ b/src/test/java/com/android/tools/r8/debug/ContinuousSteppingTest.java
@@ -105,7 +105,7 @@ } public static boolean fromAndroidN(Version dexVmVersion) { - return dexVmVersion.isAtLeast(Version.V7_0_0); + return dexVmVersion.isNewerThanOrEqual(Version.V7_0_0); } private static List<Path> findAllJarsIn(Path root) {
diff --git a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java index a083bcf..c34c633 100644 --- a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java +++ b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
@@ -1050,8 +1050,8 @@ artCommandBuilder.appendArtOption("-Xcompiler-option"); artCommandBuilder.appendArtOption("--debuggable"); } - if (ToolHelper.getDexVm().getVersion().isAtLeast(DexVm.Version.V9_0_0) && - ToolHelper.getDexVm().getVersion() != DexVm.Version.DEFAULT) { + if (ToolHelper.getDexVm().getVersion().isNewerThanOrEqual(DexVm.Version.V9_0_0) + && ToolHelper.getDexVm().getVersion() != DexVm.Version.DEFAULT) { artCommandBuilder.appendArtOption("-XjdwpProvider:internal"); } if (DEBUG_TESTS && ToolHelper.getDexVm().getVersion().isNewerThan(Version.V4_4_4)) {
diff --git a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java index 67e62e8..12c6bc8 100644 --- a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java +++ b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
@@ -338,7 +338,7 @@ // See verifyStateLocation in DebugTestBase. Assume.assumeTrue( "Streaming on Dalvik DEX runtimes has some unknown interference issue", - ToolHelper.getDexVm().getVersion().isAtLeast(Version.V6_0_1)); + ToolHelper.getDexVm().getVersion().isNewerThanOrEqual(Version.V6_0_1)); Assume.assumeTrue( "Skipping test " + testName.getMethodName()
diff --git a/src/test/java/com/android/tools/r8/debug/IincDebugTestRunner.java b/src/test/java/com/android/tools/r8/debug/IincDebugTestRunner.java index cfd0a98..3e7367e 100644 --- a/src/test/java/com/android/tools/r8/debug/IincDebugTestRunner.java +++ b/src/test/java/com/android/tools/r8/debug/IincDebugTestRunner.java
@@ -72,7 +72,7 @@ // See verifyStateLocation in DebugTestBase. Assume.assumeTrue( "Streaming on Dalvik DEX runtimes has some unknown interference issue", - ToolHelper.getDexVm().getVersion().isAtLeast(Version.V6_0_1)); + ToolHelper.getDexVm().getVersion().isNewerThanOrEqual(Version.V6_0_1)); Assume.assumeTrue( "Skipping test " + testName.getMethodName()
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPrivateSuperClassTest.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPrivateSuperClassTest.java new file mode 100644 index 0000000..6ba2e12 --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPrivateSuperClassTest.java
@@ -0,0 +1,81 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.desugar; + +import static org.junit.Assume.assumeTrue; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.utils.AndroidApiLevel; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +/** + * Regression test code for ensuring that desugared code behaves at least kind of like + * https://bugs.openjdk.java.net/browse/JDK-8021581 + */ +@RunWith(Parameterized.class) +public class DefaultLambdaMethodWithPrivateSuperClassTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(); + } + + public DefaultLambdaMethodWithPrivateSuperClassTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testJvm() throws Exception { + assumeTrue(parameters.isCfRuntime()); + testForJvm() + .addInnerClasses(getClass()) + .run(parameters.getRuntime(), Main.class) + .assertFailureWithErrorThatThrows(IllegalAccessError.class); + } + + @Test + public void testDesugar() throws Exception { + testForD8(parameters.getBackend()) + .addInnerClasses(getClass()) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .applyIf( + parameters.isCfRuntime() + || parameters.getApiLevel().isLessThanOrEqualTo(AndroidApiLevel.M), + r -> r.assertFailureWithErrorThatThrows(IllegalAccessError.class), + // TODO(b/152199517): Should be illegal access for DEX. + r -> r.assertSuccessWithOutputLines("interface")); + } + + interface Named { + + default String name() { + return "interface"; + } + + class PrivateNameBase { + private String name() { + throw new AssertionError("shouldn't get here"); + } + } + + class PrivateName extends PrivateNameBase implements Named {} + } + + public static class Main { + + public static void main(String[] args) { + String unexpected = new Named.PrivateName().name(); + System.out.println(unexpected); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPublicSuperClassTest.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPublicSuperClassTest.java new file mode 100644 index 0000000..a439984 --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPublicSuperClassTest.java
@@ -0,0 +1,71 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.desugar; + +import static org.junit.Assume.assumeTrue; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +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 DefaultLambdaMethodWithPublicSuperClassTest extends TestBase { + + private final TestParameters parameters; + private final String EXPECTED = "PublicNameBase::name"; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(); + } + + public DefaultLambdaMethodWithPublicSuperClassTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testJvm() throws Exception { + assumeTrue(parameters.isCfRuntime()); + testForJvm() + .addInnerClasses(getClass()) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines(EXPECTED); + } + + @Test + public void testDesugar() throws Exception { + testForD8(parameters.getBackend()) + .addInnerClasses(getClass()) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines(EXPECTED); + } + + interface Named { + + default String name() { + return "interface"; + } + + class PublicNameBase { + public String name() { + return "PublicNameBase::name"; + } + } + + class PublicName extends PublicNameBase implements Named {} + } + + public static class Main { + + public static void main(String[] args) { + System.out.println(new Named.PublicName().name()); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java index 477af87..409d776 100644 --- a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java +++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java
@@ -178,8 +178,8 @@ DisassembleCommand.builder().addProgramFiles(out1).setOutputPath(dissasemble1).build()); Disassemble.disassemble( DisassembleCommand.builder().addProgramFiles(out2).setOutputPath(dissasemble2).build()); - String content1 = StringUtils.join(Files.readAllLines(dissasemble1), "\n"); - String content2 = StringUtils.join(Files.readAllLines(dissasemble2), "\n"); + String content1 = StringUtils.join("\n", Files.readAllLines(dissasemble1)); + String content2 = StringUtils.join("\n", Files.readAllLines(dissasemble2)); assertEquals(content1, content2); } }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java index 784e875..646dbf9 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java
@@ -102,10 +102,7 @@ .apply(this::configureProgram) .setIncludeClassesChecksum(true) .compile() - .run( - parameters.getRuntime(), - testClassName, - parameters.getRuntime().asDex().getVm().getVersion().toString()) + .run(parameters.getRuntime(), testClassName) .assertSuccess() .inspect(this::assertDesugaring); }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomMapHierarchyTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomMapHierarchyTest.java new file mode 100644 index 0000000..57d8867 --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomMapHierarchyTest.java
@@ -0,0 +1,162 @@ +// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.desugar.desugaredlibrary; + +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.shaking.ProguardKeepAttributes; +import com.android.tools.r8.utils.BooleanUtils; +import com.android.tools.r8.utils.StringUtils; +import java.nio.file.Path; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assume; +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 CustomMapHierarchyTest extends DesugaredLibraryTestBase { + + private static final String EXPECTED = + StringUtils.lines("B::getOrDefault", "default 1", "B::getOrDefault", "default 2"); + + private final TestParameters parameters; + private final boolean shrinkDesugaredLibrary; + + @Parameters(name = "{0}, shrinkDesugaredLibrary: {1}") + public static List<Object[]> data() { + return buildParameters( + getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(), + BooleanUtils.values()); + } + + public CustomMapHierarchyTest(TestParameters parameters, boolean shrinkDesugaredLibrary) { + this.parameters = parameters; + this.shrinkDesugaredLibrary = shrinkDesugaredLibrary; + } + + @Test + public void testWithoutLibraryDesugaring() throws Exception { + Assume.assumeTrue( + parameters.getRuntime().isCf() + || parameters + .getApiLevel() + .isGreaterThanOrEqualTo(TestBase.apiLevelWithDefaultInterfaceMethodsSupport())); + testForRuntime(parameters) + .addInnerClasses(CustomMapHierarchyTest.class) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutput(EXPECTED); + } + + @Test + public void testD8() throws Exception { + Assume.assumeTrue(parameters.getRuntime().isDex()); + KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters); + testForD8() + .addInnerClasses(CustomMapHierarchyTest.class) + .setMinApi(parameters.getApiLevel()) + .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer) + .compile() + .addDesugaredCoreLibraryRunClassPath( + this::buildDesugaredLibrary, + parameters.getApiLevel(), + keepRuleConsumer.get(), + shrinkDesugaredLibrary) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutput(EXPECTED); + } + + @Test + public void testD8Cf2Cf() throws Exception { + KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters); + + Path jar = + testForD8(Backend.CF) + .addInnerClasses(CustomMapHierarchyTest.class) + .setMinApi(parameters.getApiLevel()) + .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer) + .setIncludeClassesChecksum(true) + .setMinApi(parameters.getApiLevel()) + .allowStdoutMessages() + .compile() + .writeToZip(); + String desugaredLibraryKeepRules = ""; + if (shrinkDesugaredLibrary && keepRuleConsumer.get() != null) { + // Collection keep rules is only implemented in the DEX writer. + assertEquals(0, keepRuleConsumer.get().length()); + desugaredLibraryKeepRules = "-keep class * { *; }"; + } + if (parameters.getRuntime().isDex()) { + testForD8() + .addProgramFiles(jar) + .setMinApi(parameters.getApiLevel()) + .disableDesugaring() + .allowStdoutMessages() + .compile() + .addDesugaredCoreLibraryRunClassPath( + this::buildDesugaredLibrary, + parameters.getApiLevel(), + desugaredLibraryKeepRules, + shrinkDesugaredLibrary) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutput(EXPECTED); + } else { + testForJvm() + .addProgramFiles(jar) + .addRunClasspathFiles(getDesugaredLibraryInCF(parameters, options -> {})) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutput(EXPECTED); + } + } + + @Test + public void testR8() throws Exception { + Assume.assumeTrue(parameters.getRuntime().isDex()); + KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters); + testForR8(parameters.getBackend()) + .addInnerClasses(CustomMapHierarchyTest.class) + .addKeepMainRule(Main.class) + .addKeepAllClassesRuleWithAllowObfuscation() + .addKeepAttributes( + ProguardKeepAttributes.SIGNATURE, + ProguardKeepAttributes.INNER_CLASSES, + ProguardKeepAttributes.ENCLOSING_METHOD) + .setMinApi(parameters.getApiLevel()) + .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer) + .compile() + .addDesugaredCoreLibraryRunClassPath( + this::buildDesugaredLibrary, + parameters.getApiLevel(), + keepRuleConsumer.get(), + shrinkDesugaredLibrary) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutput(EXPECTED); + } + + public static class Main { + public static void main(String[] args) { + System.out.println(new B<String>().getOrDefault("Not found", "default 1")); + System.out.println( + ((Map<String, String>) new B<String>()).getOrDefault("Not found", "default 2")); + } + } + + abstract static class A<T> extends LinkedHashMap<T, T> {} + + // AbstractSequentialList implements List further up the hierarchy. + static class B<T> extends A<T> { + // Need at least one overridden default method for emulated dispatch. + @Override + public T getOrDefault(Object key, T defaultValue) { + System.out.println("B::getOrDefault"); + return super.getOrDefault(key, defaultValue); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java index a3b768d..af6ca9e 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
@@ -9,15 +9,23 @@ import static org.junit.Assert.assertEquals; import com.android.tools.r8.NeverInline; +import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.shaking.ProguardKeepAttributes; +import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.BooleanUtils; import com.android.tools.r8.utils.StringUtils; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; +import java.io.Serializable; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.nio.file.Path; import java.time.LocalDate; +import java.util.AbstractSequentialList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.function.UnaryOperator; import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; @@ -29,7 +37,6 @@ private final TestParameters parameters; private final boolean shrinkDesugaredLibrary; - private static final String EXPECTED = StringUtils.lines("1970", "1", "2"); @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}") public static List<Object[]> data() { @@ -60,7 +67,7 @@ keepRuleConsumer.get(), shrinkDesugaredLibrary) .run(parameters.getRuntime(), Main.class) - .assertSuccessWithOutput(EXPECTED); + .assertSuccessWithOutput(expected(parameters, false)); } @Test @@ -96,13 +103,13 @@ desugaredLibraryKeepRules, shrinkDesugaredLibrary) .run(parameters.getRuntime(), Main.class) - .assertSuccessWithOutput(EXPECTED); + .assertSuccessWithOutput(expected(parameters, true)); } else { testForJvm() .addProgramFiles(jar) .addRunClasspathFiles(getDesugaredLibraryInCF(parameters, options -> {})) .run(parameters.getRuntime(), Main.class) - .assertSuccessWithOutput(EXPECTED); + .assertSuccessWithOutput(expected(parameters, true)); } } @@ -129,7 +136,7 @@ keepRuleConsumer.get(), shrinkDesugaredLibrary) .run(parameters.getRuntime(), Main.class) - .assertSuccessWithOutput(EXPECTED); + .assertSuccessWithOutput(expected(parameters, false)); } private void checkRewrittenSignature(CodeInspector inspector) { @@ -149,6 +156,7 @@ } public interface Box<T> { + T addOne(T t); } @@ -161,6 +169,61 @@ } } + private static String expected( + TestParameters parameters, boolean genericSignaturesOnEmulatedInterfaces) { + final String EXPECTED = StringUtils.lines("Box", "1970", "1", "2"); + final String STRING_KEY_HASH_MAP_EXPECTED = + StringUtils.lines( + "StringKeyHashMap", "1", "j$.util.Map<java.lang.String, T>", "2", "true", "true"); + final String SAME_KEY_AND_VALUE_TYPE_HASH_MAP_EXPECTED = + StringUtils.lines( + "SameKeyAndValueTypeHashMap", "1", "j$.util.Map<T, T>", "2", "true", "true"); + final String TRANSFORMING_SEQUENTIAL_LIST_EXPECTED = + StringUtils.lines("TransformingSequentialList", "2", "j$.util.List<T>"); + + final String EXPECTED_WITH_EMULATED_INTERFACE = + STRING_KEY_HASH_MAP_EXPECTED + + SAME_KEY_AND_VALUE_TYPE_HASH_MAP_EXPECTED + + TRANSFORMING_SEQUENTIAL_LIST_EXPECTED; + final String EXPECTED_WITHOUT_EMULATED_INTERFACE_ART_BEFORE_O = + StringUtils.lines( + "StringKeyHashMap", + "1", + "interface j$.util.Map", + "SameKeyAndValueTypeHashMap", + "1", + "interface j$.util.Map", + "TransformingSequentialList", + "2", + "interface j$.util.List"); + final String EXPECTED_WITHOUT_EMULATED_INTERFACE_JVM_AND_ART_FROM_O = + StringUtils.lines( + "StringKeyHashMap", + "0", + "SameKeyAndValueTypeHashMap", + "0", + "TransformingSequentialList", + "1"); + + return EXPECTED + + (genericSignaturesOnEmulatedInterfaces + && !parameters + .getApiLevel() + .isGreaterThanOrEqualTo(TestBase.apiLevelWithDefaultInterfaceMethodsSupport()) + ? EXPECTED_WITH_EMULATED_INTERFACE + : (parameters.isDexRuntime() + && (parameters + .getRuntime() + .asDex() + .getMinApiLevel() + .isLessThan(AndroidApiLevel.N) + || parameters + .getApiLevel() + .isLessThan(TestBase.apiLevelWithDefaultInterfaceMethodsSupport()))) + ? EXPECTED_WITHOUT_EMULATED_INTERFACE_ART_BEFORE_O + : EXPECTED_WITHOUT_EMULATED_INTERFACE_JVM_AND_ART_FROM_O); + } + public static class Main { public static Box<java.time.LocalDate> bar() { @@ -168,10 +231,96 @@ } public static void main(String[] args) { + testBox(); + testEmulatedInterfaceGenericSignatureStringKeyHashMap(); + testEmulatedInterfaceGenericSignatureSameKeyAndValueTypeHashMap(); + testEmulatedInterfaceGenericSignatureTransformingSequentialList(); + } + + public static void testBox() { + System.out.println("Box"); LocalDate localDate = bar().addOne(LocalDate.of(1970, 1, 1)); System.out.println(localDate.getYear()); System.out.println(localDate.getMonthValue()); System.out.println(localDate.getDayOfMonth()); } + + public static void testEmulatedInterfaceGenericSignatureStringKeyHashMap() { + System.out.println("StringKeyHashMap"); + Class<?> clazz = StringKeyHashMap.class; + System.out.println(clazz.getGenericInterfaces().length); + if (clazz.getGenericInterfaces().length == 0) { + return; + } + Type genericInterface = clazz.getGenericInterfaces()[0]; + System.out.println(genericInterface); + if (genericInterface instanceof ParameterizedType) { + // The j$.util.Map emulated interface has the generic type arguments <String, T>. + Type[] actualTypeArguments = + ((ParameterizedType) genericInterface).getActualTypeArguments(); + System.out.println(actualTypeArguments.length); + System.out.println(actualTypeArguments[0].equals(String.class)); + System.out.println(actualTypeArguments[1].equals(clazz.getTypeParameters()[0])); + } + } + + public static void testEmulatedInterfaceGenericSignatureSameKeyAndValueTypeHashMap() { + System.out.println("SameKeyAndValueTypeHashMap"); + Class<?> clazz = SameKeyAndValueTypeHashMap.class; + System.out.println(clazz.getGenericInterfaces().length); + if (clazz.getGenericInterfaces().length == 0) { + return; + } + Type genericInterface = clazz.getGenericInterfaces()[0]; + System.out.println(genericInterface); + if (genericInterface instanceof ParameterizedType) { + // The j$.util.Map emulated interface has the generic type arguments <T, T>. + Type[] actualTypeArguments = + ((ParameterizedType) genericInterface).getActualTypeArguments(); + System.out.println(actualTypeArguments.length); + System.out.println(actualTypeArguments[0].equals(clazz.getTypeParameters()[0])); + System.out.println(actualTypeArguments[1].equals(clazz.getTypeParameters()[0])); + } + } + + public static void testEmulatedInterfaceGenericSignatureTransformingSequentialList() { + System.out.println("TransformingSequentialList"); + Class<?> clazz = TransformingSequentialList.class; + System.out.println(clazz.getGenericInterfaces().length); + if (clazz.getGenericInterfaces().length == 1) { + return; + } + // j$.util.List emulated interface has the generic type argument <T>. + System.out.println(clazz.getGenericInterfaces()[1]); + } + } + + // LinkedHashMap implements Map. + abstract static class StringKeyHashMap<T> extends LinkedHashMap<String, T> { + + // Need at least one overridden default method for emulated dispatch. + @Override + public T getOrDefault(Object key, T defaultValue) { + return super.getOrDefault(key, defaultValue); + } + } + + // LinkedHashMap implements Map. + abstract static class SameKeyAndValueTypeHashMap<T> extends LinkedHashMap<T, T> { + + // Need at least one overridden default method for emulated dispatch. + @Override + public T getOrDefault(Object key, T defaultValue) { + return super.getOrDefault(key, defaultValue); + } + } + + // AbstractSequentialList implements List further up the hierarchy. + abstract static class TransformingSequentialList<F, T> extends AbstractSequentialList<T> + implements Serializable { + + // Need at least one overridden default method for emulated dispatch. + @Override + public void replaceAll(UnaryOperator<T> operator) {} } }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DumpCoreLibUsage.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DumpCoreLibUsage.java index 62d2d3a..ae4eda0 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DumpCoreLibUsage.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DumpCoreLibUsage.java
@@ -85,13 +85,13 @@ if (!field.accessFlags.isPublic()) { continue; } - if (filter.contains(field.field)) { + if (filter.contains(field.getReference())) { continue; } - if (usesTypeFromPackage(pkg, field.field)) { + if (usesTypeFromPackage(pkg, field.getReference())) { headerWritten = writeHeaderIfNeeded(libraryClass.type, headerWritten); System.out.println(" " + field.toSourceString()); - found.add(field.field); + found.add(field.getReference()); } } @@ -105,13 +105,13 @@ if (method.isSyntheticMethod()) { continue; } - if (filter.contains(method.method)) { + if (filter.contains(method.getReference())) { continue; } - if (usesTypeFromPackage(pkg, method.method)) { + if (usesTypeFromPackage(pkg, method.getReference())) { headerWritten = writeHeaderIfNeeded(libraryClass.type, headerWritten); - System.out.println(" " + method.method.toSourceStringWithoutHolder()); - found.add(method.method); + System.out.println(" " + method.getReference().toSourceStringWithoutHolder()); + found.add(method.getReference()); } }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilFunctionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilFunctionTest.java index e345069..32d9d95 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilFunctionTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilFunctionTest.java
@@ -16,7 +16,6 @@ import com.android.tools.r8.utils.codeinspector.CodeInspector; import java.util.List; import java.util.function.Function; -import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -51,7 +50,7 @@ classSubject .uniqueMethodWithName("applyFunction") .getMethod() - .method + .getReference() .proto .parameters .values[0]
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 43f53ab..624e8a0 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
@@ -11,6 +11,8 @@ import com.android.tools.r8.GenerateLintFiles; import com.android.tools.r8.StringResource; import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.ToolHelper; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration; @@ -26,9 +28,22 @@ import java.util.List; import org.junit.Assume; 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 LintFilesTest extends TestBase { + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + public LintFilesTest(TestParameters parameters) { + parameters.assertNoneRuntime(); + } + private void checkFileContent(AndroidApiLevel minApiLevel, Path lintFile) throws Exception { // Just do some light probing in the generated lint files. List<String> methods = FileUtils.readAllLines(lintFile);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/CallBackConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/CallBackConversionTest.java index cb8c24f..e23e86d 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/CallBackConversionTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/CallBackConversionTest.java
@@ -64,7 +64,7 @@ .anyMatch( m -> m.getMethod() - .method + .getReference() .proto .parameters .values[0] @@ -75,7 +75,7 @@ .anyMatch( m -> m.getMethod() - .method + .getReference() .proto .parameters .values[0] @@ -210,9 +210,9 @@ virtualMethods.stream() .anyMatch( m -> - m.getMethod().method.name.toString().equals("foo") + m.getMethod().getReference().name.toString().equals("foo") && m.getMethod() - .method + .getReference() .proto .parameters .values[0]
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java index 0ee446d..5cd8c8d 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
@@ -121,7 +121,7 @@ IterableUtils.size( myCollection .getDexProgramClass() - .virtualMethods(m -> m.method.name.toString().equals("forEach")))); + .virtualMethods(m -> m.getReference().name.toString().equals("forEach")))); } private void assertWrapperMethodsPresent(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MinimumNumberOfBridgesGenerated.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MinimumNumberOfBridgesGenerated.java index b38e710..47320d8 100644 --- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MinimumNumberOfBridgesGenerated.java +++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MinimumNumberOfBridgesGenerated.java
@@ -86,16 +86,19 @@ private boolean isNestBridge(FoundMethodSubject methodSubject) { DexEncodedMethod method = methodSubject.getMethod(); if (method.isInstanceInitializer()) { - if (method.method.proto.parameters.isEmpty()) { + if (method.getReference().proto.parameters.isEmpty()) { return false; } - DexType[] formals = method.method.proto.parameters.values; + DexType[] formals = method.getReference().proto.parameters.values; DexType lastFormal = formals[formals.length - 1]; return lastFormal.isClassType() && SyntheticItemsTestUtils.isInitializerTypeArgument( Reference.classFromDescriptor(lastFormal.toDescriptorString())); } - return method.method.name.toString() + return method + .getReference() + .name + .toString() .startsWith(NestBasedAccessDesugaring.NEST_ACCESS_NAME_PREFIX); } }
diff --git a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java index 2e97d1e..9f9dd85 100644 --- a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java +++ b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
@@ -13,6 +13,7 @@ import com.android.tools.r8.utils.StringUtils; import java.nio.file.Path; import java.util.List; +import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -35,20 +36,35 @@ public static List<Object[]> data() { // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk15). return buildParameters( - getTestParameters().withCustomRuntime(CfRuntime.getCheckedInJdk15()).build()); + getTestParameters() + .withCustomRuntime(CfRuntime.getCheckedInJdk15()) + .withDexRuntimes() + .withAllApiLevelsAlsoForCf() + .build()); } @Test - public void testJvm() throws Exception { - testForJvm() + public void testD8AndJvm() throws Exception { + if (parameters.isCfRuntime()) { + testForJvm() + .addProgramClassFileData(PROGRAM_DATA) + .enablePreview() + .run(parameters.getRuntime(), MAIN_TYPE) + .assertSuccessWithOutput(EXPECTED_RESULT); + } + testForD8(parameters.getBackend()) .addProgramClassFileData(PROGRAM_DATA) - .enablePreview() + .setMinApi(parameters.getApiLevel()) + .addOptionsModification(TestingOptions::allowExperimentClassFileVersion) + .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true) + .compile() .run(parameters.getRuntime(), MAIN_TYPE) .assertSuccessWithOutput(EXPECTED_RESULT); } @Test public void testR8Cf() throws Exception { + Assume.assumeTrue(parameters.isCfRuntime()); Path output = testForR8(parameters.getBackend()) .addProgramClassFileData(PROGRAM_DATA)
diff --git a/src/test/java/com/android/tools/r8/desugar/records/GenerateRecordMethods.java b/src/test/java/com/android/tools/r8/desugar/records/GenerateRecordMethods.java new file mode 100644 index 0000000..53d6201 --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugar/records/GenerateRecordMethods.java
@@ -0,0 +1,118 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.desugar.records; + +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.TestRuntime.CfVm; +import com.android.tools.r8.cf.code.CfInstruction; +import com.android.tools.r8.cf.code.CfInvoke; +import com.android.tools.r8.cf.code.CfTypeInstruction; +import com.android.tools.r8.cfmethodgeneration.MethodGenerationBase; +import com.android.tools.r8.graph.CfCode; +import com.android.tools.r8.graph.DexItemFactory; +import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.DexString; +import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.ir.desugar.RecordRewriter; +import com.android.tools.r8.utils.FileUtils; +import com.google.common.collect.ImmutableList; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; +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 GenerateRecordMethods extends MethodGenerationBase { + private final DexType GENERATED_TYPE = + factory.createType("Lcom/android/tools/r8/ir/desugar/RecordCfMethods;"); + private final List<Class<?>> METHOD_TEMPLATE_CLASSES = ImmutableList.of(RecordMethods.class); + + protected final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withCfRuntime(CfVm.JDK9).build(); + } + + public GenerateRecordMethods(TestParameters parameters) { + this.parameters = parameters; + } + + @Override + protected DexType getGeneratedType() { + return GENERATED_TYPE; + } + + @Override + protected List<Class<?>> getMethodTemplateClasses() { + return METHOD_TEMPLATE_CLASSES; + } + + @Override + protected int getYear() { + return 2021; + } + + @Override + protected CfCode getCode(String holderName, String methodName, CfCode code) { + DexType recordStubType = + factory.createType("Lcom/android/tools/r8/desugar/records/RecordMethods$RecordStub;"); + code.setInstructions( + code.getInstructions().stream() + .map(instruction -> rewriteRecordStub(factory, instruction, recordStubType)) + .collect(Collectors.toList())); + return code; + } + + private CfInstruction rewriteRecordStub( + DexItemFactory factory, CfInstruction instruction, DexType recordStubType) { + if (instruction.isTypeInstruction()) { + CfTypeInstruction typeInstruction = instruction.asTypeInstruction(); + return typeInstruction.withType( + rewriteType(factory, recordStubType, typeInstruction.getType())); + } + if (instruction.isInvoke()) { + CfInvoke cfInvoke = instruction.asInvoke(); + DexMethod method = cfInvoke.getMethod(); + DexMethod newMethod = + factory.createMethod( + rewriteType(factory, recordStubType, method.holder), + method.proto, + rewriteName(method.name)); + return new CfInvoke(cfInvoke.getOpcode(), newMethod, cfInvoke.isInterface()); + } + return instruction; + } + + private String rewriteName(DexString name) { + return name.toString().equals("getFieldsAsObjects") + ? RecordRewriter.GET_FIELDS_AS_OBJECTS_METHOD_NAME + : name.toString(); + } + + private DexType rewriteType(DexItemFactory factory, DexType recordStubType, DexType type) { + return type == recordStubType ? factory.recordType : type; + } + + @Test + public void testRecordMethodsGenerated() throws Exception { + ArrayList<Class<?>> sorted = new ArrayList<>(getMethodTemplateClasses()); + sorted.sort(Comparator.comparing(Class::getTypeName)); + assertEquals("Classes should be listed in sorted order", sorted, getMethodTemplateClasses()); + assertEquals( + FileUtils.readTextFile(getGeneratedFile(), StandardCharsets.UTF_8), generateMethods()); + } + + public static void main(String[] args) throws Exception { + new GenerateRecordMethods(null).generateMethodsAndWriteThemToFile(); + } +}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java index 5fce5e2..d388ac4 100644 --- a/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java +++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java
@@ -13,6 +13,7 @@ import com.android.tools.r8.utils.StringUtils; import java.nio.file.Path; import java.util.List; +import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -35,20 +36,35 @@ public static List<Object[]> data() { // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk15). return buildParameters( - getTestParameters().withCustomRuntime(CfRuntime.getCheckedInJdk15()).build()); + getTestParameters() + .withCustomRuntime(CfRuntime.getCheckedInJdk15()) + .withDexRuntimes() + .withAllApiLevelsAlsoForCf() + .build()); } @Test - public void testJvm() throws Exception { - testForJvm() + public void testD8AndJvm() throws Exception { + if (parameters.isCfRuntime()) { + testForJvm() + .addProgramClassFileData(PROGRAM_DATA) + .enablePreview() + .run(parameters.getRuntime(), MAIN_TYPE) + .assertSuccessWithOutput(EXPECTED_RESULT); + } + testForD8(parameters.getBackend()) .addProgramClassFileData(PROGRAM_DATA) - .enablePreview() + .setMinApi(parameters.getApiLevel()) + .addOptionsModification(TestingOptions::allowExperimentClassFileVersion) + .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true) + .compile() .run(parameters.getRuntime(), MAIN_TYPE) .assertSuccessWithOutput(EXPECTED_RESULT); } @Test public void testR8Cf() throws Exception { + Assume.assumeTrue(parameters.isCfRuntime()); Path output = testForR8(parameters.getBackend()) .addProgramClassFileData(PROGRAM_DATA)
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java index 071af85..711909f 100644 --- a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java +++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
@@ -13,6 +13,7 @@ import com.android.tools.r8.utils.StringUtils; import java.nio.file.Path; import java.util.List; +import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -48,20 +49,35 @@ public static List<Object[]> data() { // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk15). return buildParameters( - getTestParameters().withCustomRuntime(CfRuntime.getCheckedInJdk15()).build()); + getTestParameters() + .withCustomRuntime(CfRuntime.getCheckedInJdk15()) + .withDexRuntimes() + .withAllApiLevelsAlsoForCf() + .build()); } @Test - public void testJvm() throws Exception { - testForJvm() + public void testD8AndJvm() throws Exception { + if (parameters.isCfRuntime()) { + testForJvm() + .addProgramClassFileData(PROGRAM_DATA) + .enablePreview() + .run(parameters.getRuntime(), MAIN_TYPE) + .assertSuccessWithOutput(EXPECTED_RESULT); + } + testForD8(parameters.getBackend()) .addProgramClassFileData(PROGRAM_DATA) - .enablePreview() + .setMinApi(parameters.getApiLevel()) + .addOptionsModification(TestingOptions::allowExperimentClassFileVersion) + .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true) + .compile() .run(parameters.getRuntime(), MAIN_TYPE) .assertSuccessWithOutput(EXPECTED_RESULT); } @Test public void testR8Cf() throws Exception { + Assume.assumeTrue(parameters.isCfRuntime()); Path output = testForR8(parameters.getBackend()) .addProgramClassFileData(PROGRAM_DATA)
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java new file mode 100644 index 0000000..bd08a25 --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
@@ -0,0 +1,101 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.desugar.records; + +import com.android.tools.r8.D8TestCompileResult; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestRuntime.CfRuntime; +import com.android.tools.r8.utils.InternalOptions.TestingOptions; +import com.android.tools.r8.utils.StringUtils; +import java.nio.file.Path; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class RecordMergeTest extends TestBase { + + private static final String RECORD_NAME_1 = "RecordWithMembers"; + private static final byte[][] PROGRAM_DATA_1 = RecordTestUtils.getProgramData(RECORD_NAME_1); + private static final String MAIN_TYPE_1 = RecordTestUtils.getMainType(RECORD_NAME_1); + private static final String EXPECTED_RESULT_1 = + StringUtils.lines( + "BobX", "43", "BobX", "43", "FelixX", "-1", "FelixX", "-1", "print", "Bob43", "extra"); + + private static final String RECORD_NAME_2 = "SimpleRecord"; + private static final byte[][] PROGRAM_DATA_2 = RecordTestUtils.getProgramData(RECORD_NAME_2); + private static final String MAIN_TYPE_2 = RecordTestUtils.getMainType(RECORD_NAME_2); + private static final String EXPECTED_RESULT_2 = + StringUtils.lines("Jane Doe", "42", "Jane Doe", "42"); + + private final TestParameters parameters; + + public RecordMergeTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Parameterized.Parameters(name = "{0}") + public static List<Object[]> data() { + // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk15). + return buildParameters( + getTestParameters() + .withCustomRuntime(CfRuntime.getCheckedInJdk15()) + .withDexRuntimes() + .withAllApiLevelsAlsoForCf() + .build()); + } + + @Test + public void testMergeDesugaredInputs() throws Exception { + Path output1 = + testForD8(parameters.getBackend()) + .addProgramClassFileData(PROGRAM_DATA_1) + .setMinApi(parameters.getApiLevel()) + .addOptionsModification(TestingOptions::allowExperimentClassFileVersion) + .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true) + .compile() + .writeToZip(); + Path output2 = + testForD8(parameters.getBackend()) + .addProgramClassFileData(PROGRAM_DATA_2) + .setMinApi(parameters.getApiLevel()) + .addOptionsModification(TestingOptions::allowExperimentClassFileVersion) + .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true) + .compile() + .writeToZip(); + D8TestCompileResult result = + testForD8(parameters.getBackend()) + .addProgramFiles(output1, output2) + .setMinApi(parameters.getApiLevel()) + .addOptionsModification(TestingOptions::allowExperimentClassFileVersion) + .compile(); + result.run(parameters.getRuntime(), MAIN_TYPE_1).assertSuccessWithOutput(EXPECTED_RESULT_1); + result.run(parameters.getRuntime(), MAIN_TYPE_2).assertSuccessWithOutput(EXPECTED_RESULT_2); + } + + @Test + public void testMergeDesugaredAndNonDesugaredInputs() throws Exception { + Path output1 = + testForD8(parameters.getBackend()) + .addProgramClassFileData(PROGRAM_DATA_1) + .setMinApi(parameters.getApiLevel()) + .addOptionsModification(TestingOptions::allowExperimentClassFileVersion) + .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true) + .compile() + .writeToZip(); + D8TestCompileResult result = + testForD8(parameters.getBackend()) + .addProgramFiles(output1) + .addProgramClassFileData(PROGRAM_DATA_2) + .setMinApi(parameters.getApiLevel()) + .addOptionsModification(TestingOptions::allowExperimentClassFileVersion) + .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true) + .compile(); + result.run(parameters.getRuntime(), MAIN_TYPE_1).assertSuccessWithOutput(EXPECTED_RESULT_1); + result.run(parameters.getRuntime(), MAIN_TYPE_2).assertSuccessWithOutput(EXPECTED_RESULT_2); + } +}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordMethods.java b/src/test/java/com/android/tools/r8/desugar/records/RecordMethods.java new file mode 100644 index 0000000..7b1b2e5 --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugar/records/RecordMethods.java
@@ -0,0 +1,43 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.desugar.records; + +import java.util.Arrays; + +// This class implements support methods for record desugaring. The RecordRewriter +// rewrites relevant calls to one of the following methods. +public class RecordMethods { + + public static String toString(RecordStub recordInstance, String simpleName, String fieldNames) { + // Example: "Person[name=Jane Doe, age=42]" + String[] fieldNamesSplit = fieldNames.isEmpty() ? new String[0] : fieldNames.split(";"); + Object[] fields = recordInstance.getFieldsAsObjects(); + StringBuilder builder = new StringBuilder(); + builder.append(simpleName).append("["); + for (int i = 0; i < fieldNamesSplit.length; i++) { + builder.append(fieldNamesSplit[i]).append("=").append(fields[i]); + if (i != fieldNamesSplit.length - 1) { + builder.append(", "); + } + } + builder.append("]"); + return builder.toString(); + } + + public static int hashCode(RecordStub recordInstance) { + return 31 * Arrays.hashCode(recordInstance.getFieldsAsObjects()) + + recordInstance.getClass().hashCode(); + } + + public static boolean equals(RecordStub recordInstance, Object other) { + return recordInstance.getClass() == other.getClass() + && Arrays.equals( + ((RecordStub) other).getFieldsAsObjects(), recordInstance.getFieldsAsObjects()); + } + + public abstract static class RecordStub { + abstract Object[] getFieldsAsObjects(); + } +}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java index 610b061..5472f22 100644 --- a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java +++ b/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
@@ -6,7 +6,6 @@ import static com.android.tools.r8.desugar.records.RecordTestUtils.RECORD_KEEP_RULE; -import com.android.tools.r8.Jdk9TestUtils; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestRuntime.CfRuntime; @@ -14,6 +13,7 @@ import com.android.tools.r8.utils.StringUtils; import java.nio.file.Path; import java.util.List; +import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -38,24 +38,38 @@ public static List<Object[]> data() { // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk15). return buildParameters( - getTestParameters().withCustomRuntime(CfRuntime.getCheckedInJdk15()).build()); + getTestParameters() + .withCustomRuntime(CfRuntime.getCheckedInJdk15()) + .withDexRuntimes() + .withAllApiLevelsAlsoForCf() + .build()); } @Test - public void testJvm() throws Exception { - testForJvm() + public void testD8AndJvm() throws Exception { + if (parameters.isCfRuntime()) { + testForJvm() + .addProgramClassFileData(PROGRAM_DATA) + .enablePreview() + .run(parameters.getRuntime(), MAIN_TYPE) + .assertSuccessWithOutput(EXPECTED_RESULT); + } + testForD8(parameters.getBackend()) .addProgramClassFileData(PROGRAM_DATA) - .enablePreview() + .setMinApi(parameters.getApiLevel()) + .addOptionsModification(TestingOptions::allowExperimentClassFileVersion) + .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true) + .compile() .run(parameters.getRuntime(), MAIN_TYPE) .assertSuccessWithOutput(EXPECTED_RESULT); } @Test public void testR8Cf() throws Exception { + Assume.assumeTrue(parameters.isCfRuntime()); Path output = testForR8(parameters.getBackend()) .addProgramClassFileData(PROGRAM_DATA) - .addLibraryFiles(Jdk9TestUtils.getJdk9LibraryFiles(temp)) .setMinApi(parameters.getApiLevel()) .addKeepRules(RECORD_KEEP_RULE) .addKeepMainRule(MAIN_TYPE)
diff --git a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java index d5d2b1a..4820c08 100644 --- a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java +++ b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
@@ -40,7 +40,7 @@ getTestParameters() .withCustomRuntime(CfRuntime.getCheckedInJdk15()) .withDexRuntimes() - .withAllApiLevels() + .withAllApiLevelsAlsoForCf() .build()); } @@ -52,10 +52,8 @@ .enablePreview() .run(parameters.getRuntime(), MAIN_TYPE) .assertSuccessWithOutput(EXPECTED_RESULT); - // TODO(b/179146128): Add a test for D8 cf to cf. - return; } - testForD8() + testForD8(parameters.getBackend()) .addProgramClassFileData(PROGRAM_DATA) .setMinApi(parameters.getApiLevel()) .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithStaticResolutionInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionInvokeVirtualTest.java similarity index 96% rename from src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithStaticResolutionInvokeVirtualTest.java rename to src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionInvokeVirtualTest.java index e2474ca..cd2b968 100644 --- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithStaticResolutionInvokeVirtualTest.java +++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionInvokeVirtualTest.java
@@ -22,7 +22,7 @@ import org.objectweb.asm.Opcodes; @RunWith(Parameterized.class) -public class DefaultInterfaceMethodDesugaringWithStaticResolutionInvokeVirtualTest +public class DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionInvokeVirtualTest extends TestBase { private static final String EXPECTED = StringUtils.lines("I.m()"); @@ -36,7 +36,7 @@ getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values()); } - public DefaultInterfaceMethodDesugaringWithStaticResolutionInvokeVirtualTest( + public DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionInvokeVirtualTest( TestParameters parameters, boolean invalidInvoke) { this.parameters = parameters; this.invalidInvoke = invalidInvoke;
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithStaticResolutionTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionTest.java similarity index 75% rename from src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithStaticResolutionTest.java rename to src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionTest.java index c649c8d..3a55d74 100644 --- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithStaticResolutionTest.java +++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionTest.java
@@ -1,3 +1,6 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.desugaring.interfacemethods; import static org.junit.Assume.assumeTrue; @@ -11,7 +14,7 @@ import org.junit.runners.Parameterized; @RunWith(Parameterized.class) -public class DefaultInterfaceMethodDesugaringWithStaticResolutionTest extends TestBase { +public class DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionTest extends TestBase { private static final String EXPECTED = StringUtils.lines("I.m()"); @@ -22,7 +25,8 @@ return getTestParameters().withAllRuntimesAndApiLevels().build(); } - public DefaultInterfaceMethodDesugaringWithStaticResolutionTest(TestParameters parameters) { + public DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionTest( + TestParameters parameters) { this.parameters = parameters; } @@ -39,7 +43,7 @@ public void testD8() throws Exception { assumeTrue(parameters.isDexRuntime()); testForD8() - .addInnerClasses(DefaultInterfaceMethodDesugaringWithStaticResolutionTest.class) + .addInnerClasses(DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionTest.class) .setMinApi(parameters.getApiLevel()) .compile() .run(parameters.getRuntime(), TestClass.class) @@ -49,7 +53,7 @@ @Test public void testR8() throws Exception { testForR8(parameters.getBackend()) - .addInnerClasses(DefaultInterfaceMethodDesugaringWithStaticResolutionTest.class) + .addInnerClasses(DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionTest.class) .addKeepAllClassesRule() .setMinApi(parameters.getApiLevel()) .compile()
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithStaticResolutionInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java similarity index 64% copy from src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithStaticResolutionInvokeVirtualTest.java copy to src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java index e2474ca..b968127 100644 --- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithStaticResolutionInvokeVirtualTest.java +++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
@@ -8,7 +8,6 @@ import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestRunResult; -import com.android.tools.r8.ToolHelper.DexVm; import com.android.tools.r8.ToolHelper.DexVm.Version; import com.android.tools.r8.utils.BooleanUtils; import com.android.tools.r8.utils.DescriptorUtils; @@ -22,10 +21,11 @@ import org.objectweb.asm.Opcodes; @RunWith(Parameterized.class) -public class DefaultInterfaceMethodDesugaringWithStaticResolutionInvokeVirtualTest +public class DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest extends TestBase { private static final String EXPECTED = StringUtils.lines("I.m()"); + private static final String EXPECTED_R8 = StringUtils.lines("B.m()"); private final TestParameters parameters; private final boolean invalidInvoke; @@ -33,10 +33,11 @@ @Parameterized.Parameters(name = "{0}, invalid:{1}") public static List<Object[]> data() { return buildParameters( - getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values()); + getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(), + BooleanUtils.values()); } - public DefaultInterfaceMethodDesugaringWithStaticResolutionInvokeVirtualTest( + public DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest( TestParameters parameters, boolean invalidInvoke) { this.parameters = parameters; this.invalidInvoke = invalidInvoke; @@ -53,8 +54,6 @@ B.class.getDeclaredMethod("m"), flags -> { assert flags.isPublic(); - flags.unsetPublic(); - flags.setPrivate(); flags.setStatic(); }) .transform(), @@ -83,7 +82,8 @@ testForRuntime(parameters) .addProgramClasses(getProgramClasses()) .addProgramClassFileData(getProgramClassData()) - .run(parameters.getRuntime(), TestClass.class)); + .run(parameters.getRuntime(), TestClass.class), + false); } @Test @@ -95,56 +95,36 @@ .addKeepAllClassesRule() .setMinApi(parameters.getApiLevel()) .compile() - .run(parameters.getRuntime(), TestClass.class)); + .run(parameters.getRuntime(), TestClass.class), + true); } - private void checkResult(TestRunResult<?> result) { + private void checkResult(TestRunResult<?> result, boolean isR8) { // Invalid invoke case is where the invoke-virtual targets C.m. if (invalidInvoke) { - // Up to 4.4 the exception for targeting a private static was ICCE. - if (isDexOlderThanOrEqual(Version.V4_4_4)) { + if (parameters.isCfRuntime()) { result.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class); return; } - // Then up to 6.0 the runtime just ignores privates leading to incorrectly hitting I.m - if (isDexOlderThanOrEqual(Version.V6_0_1)) { + if (parameters.getDexRuntimeVersion().isInRangeInclusive(Version.V5_1_1, Version.V7_0_0)) { result.assertSuccessWithOutput(EXPECTED); return; } - if (!unexpectedArtFailure() && !parameters.canUseDefaultAndStaticInterfaceMethods()) { - assert false : "Dead code until future ART behavior change. See b/152199517"; - // Desugaring will insert a forwarding bridge which will hide the "invalid invoke" case. - // Thus, a future ART runtime that does not have the invalid IAE for the private override - // will end up calling the forward method to I.m. - result.assertSuccessWithOutput(EXPECTED); - } - // The expected behavior is IAE since the resolved method is private. - result.assertFailureWithErrorThatThrows(IllegalAccessError.class); + result.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class); return; } - // The non-invalid case is where the invoke-virtual targets A.m. - - // In the successful case ART since 6.0 incorrectly throws IAE due to the private override. - if (unexpectedArtFailure()) { - result.assertFailureWithErrorThatThrows(IllegalAccessError.class); + if (isR8 + && parameters.isDexRuntime() + && parameters.getDexRuntimeVersion().isNewerThan(Version.V6_0_1)) { + // TODO(b/1822553980: This should be EXPECTED. + result.assertSuccessWithOutput(EXPECTED_R8); return; } - // The expected behavior is that the resolution of A.m will resolve and hit I.m. result.assertSuccessWithOutput(EXPECTED); } - private boolean isDexOlderThanOrEqual(Version version) { - return parameters.isDexRuntime() - && parameters.getRuntime().asDex().getVm().getVersion().isOlderThanOrEqual(version); - } - - private boolean unexpectedArtFailure() { - return parameters.isDexRuntime() - && parameters.getRuntime().asDex().getVm().isNewerThan(DexVm.ART_6_0_1_HOST); - } - static class TestClass { public static void main(String[] args) { @@ -165,7 +145,7 @@ static class B extends A { - public /* will be: private static */ void m() { + public /* will be: public static */ void m() { System.out.println("B.m()"); } }
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionOnClassTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionOnClassTest.java new file mode 100644 index 0000000..1684c5a --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionOnClassTest.java
@@ -0,0 +1,115 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.desugaring.interfacemethods; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.ToolHelper.DexVm.Version; +import com.android.tools.r8.utils.StringUtils; +import com.google.common.collect.ImmutableList; +import java.util.Collection; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class DefaultInterfaceMethodDesugaringWithPublicStaticResolutionOnClassTest + extends TestBase { + + private static final String EXPECTED_INVALID = StringUtils.lines("I.m()"); + + private final TestParameters parameters; + + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(); + } + + public DefaultInterfaceMethodDesugaringWithPublicStaticResolutionOnClassTest( + TestParameters parameters) { + this.parameters = parameters; + } + + private Collection<Class<?>> getProgramClasses() { + return ImmutableList.of(TestClass.class, I.class, B.class); + } + + private Collection<byte[]> getProgramClassData() throws Exception { + return ImmutableList.of( + transformer(A.class) + .setAccessFlags( + A.class.getDeclaredMethod("m"), + flags -> { + assertTrue(flags.isPrivate()); + assertTrue(flags.isStatic()); + flags.promoteToPublic(); + }) + .transform()); + } + + @Test + public void testJVM() throws Exception { + assumeTrue(parameters.isCfRuntime()); + testForJvm() + .addProgramClasses(getProgramClasses()) + .addProgramClassFileData(getProgramClassData()) + .run(parameters.getRuntime(), TestClass.class) + .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class); + } + + @Test + public void testD8() throws Exception { + testForD8(parameters.getBackend()) + .addProgramClasses(getProgramClasses()) + .addProgramClassFileData(getProgramClassData()) + .setMinApi(parameters.getApiLevel()) + .compile() + .run(parameters.getRuntime(), TestClass.class) + // TODO(b/182335909): Ideally, this should also throw ICCE when desugaring. + .applyIf( + !parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring() + || parameters.isDexRuntimeVersion(Version.V7_0_0), + r -> r.assertSuccessWithOutput(EXPECTED_INVALID), + r -> r.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class)); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addProgramClasses(getProgramClasses()) + .addProgramClassFileData(getProgramClassData()) + .addKeepAllClassesRule() + .setMinApi(parameters.getApiLevel()) + .compile() + .run(parameters.getRuntime(), TestClass.class) + .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class); + } + + static class TestClass { + + public static void main(String[] args) { + new B().m(); + } + } + + interface I { + + default void m() { + System.out.println("I.m()"); + } + } + + public static class A { + + private static /* will be: public static */ void m() { + System.out.println("A.m()"); + } + } + + static class B extends A implements I {} +}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionTest.java new file mode 100644 index 0000000..c442b75 --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionTest.java
@@ -0,0 +1,108 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.desugaring.interfacemethods; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.utils.StringUtils; +import com.google.common.collect.ImmutableList; +import java.util.Collection; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class DefaultInterfaceMethodDesugaringWithPublicStaticResolutionTest extends TestBase { + + private static final String EXPECTED = StringUtils.lines("I.m()"); + + private final TestParameters parameters; + + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(); + } + + public DefaultInterfaceMethodDesugaringWithPublicStaticResolutionTest(TestParameters parameters) { + this.parameters = parameters; + } + + private Collection<Class<?>> getProgramClasses() { + return ImmutableList.of(TestClass.class, I.class, B.class); + } + + private Collection<byte[]> getProgramClassData() throws Exception { + return ImmutableList.of( + transformer(A.class) + .setAccessFlags( + A.class.getDeclaredMethod("m"), + flags -> { + assertTrue(flags.isPrivate()); + assertTrue(flags.isStatic()); + flags.promoteToPublic(); + }) + .transform()); + } + + @Test + public void testJVM() throws Exception { + assumeTrue(parameters.isCfRuntime()); + testForJvm() + .addProgramClasses(getProgramClasses()) + .addProgramClassFileData(getProgramClassData()) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutput(EXPECTED); + } + + @Test + public void testD8() throws Exception { + testForD8(parameters.getBackend()) + .addProgramClasses(getProgramClasses()) + .addProgramClassFileData(getProgramClassData()) + .setMinApi(parameters.getApiLevel()) + .compile() + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutput(EXPECTED); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addProgramClasses(getProgramClasses()) + .addProgramClassFileData(getProgramClassData()) + .addKeepAllClassesRule() + .setMinApi(parameters.getApiLevel()) + .compile() + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutput(EXPECTED); + } + + static class TestClass { + + public static void main(String[] args) { + I b = new B(); + b.m(); + } + } + + interface I { + + default void m() { + System.out.println("I.m()"); + } + } + + public static class A { + + private static /* will be: public static */ void m() { + System.out.println("A.m()"); + } + } + + static class B extends A implements I {} +}
diff --git a/src/test/java/com/android/tools/r8/dump/DumpMainDexInputsTest.java b/src/test/java/com/android/tools/r8/dump/DumpMainDexInputsTest.java index 7c8eafe..1d01be7 100644 --- a/src/test/java/com/android/tools/r8/dump/DumpMainDexInputsTest.java +++ b/src/test/java/com/android/tools/r8/dump/DumpMainDexInputsTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.dump; +import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage; import static java.util.stream.Collectors.toList; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; @@ -12,7 +13,6 @@ import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; -import com.android.tools.r8.ToolHelper; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.FileUtils; import com.android.tools.r8.utils.StringUtils; @@ -89,19 +89,32 @@ "pre-native-multidex only", parameters.getApiLevel().isLessThanOrEqualTo(AndroidApiLevel.K)); Path dumpDir = temp.newFolder().toPath(); + // Pre-compile to DEX and do main-dex list on DEX inputs only. + Path dexed = + testForD8() + .addInnerClasses(DumpMainDexInputsTest.class) + .setMinApi(parameters.getApiLevel()) + .compile() + .writeToZip(); + testForD8() + .addProgramFiles(dexed) .setMinApi(parameters.getApiLevel()) - .addInnerClasses(DumpMainDexInputsTest.class) .addMainDexListFiles( mainDexListForMainDexFile1AndMainDexFile2(), mainDexListForMainDexFile3()) .addMainDexListClasses(MainDexClass1.class, MainDexClass2.class, TestClass.class) - .addLibraryFiles(ToolHelper.getJava8RuntimeJar()) .addOptionsModification(options -> options.dumpInputToDirectory = dumpDir.toString()) - .compile() - .assertAllInfoMessagesMatch(containsString("Dumped compilation inputs to:")) - .assertAllWarningMessagesMatch( - containsString( - "Dumping main dex list resources may have side effects due to I/O on Paths.")) + .compileWithExpectedDiagnostics( + diagnostics -> + diagnostics + .assertNoErrors() + .assertInfosMatch( + diagnosticMessage(containsString("Dumped compilation inputs to:"))) + .assertWarningsMatch( + diagnosticMessage( + containsString( + "Dumping main dex list resources may have side effects due to I/O" + + " on Paths.")))) .run(parameters.getRuntime(), TestClass.class) .assertSuccessWithOutputLines("Hello, world"); verifyDumpDir(dumpDir, true); @@ -117,7 +130,7 @@ .setMinApi(parameters.getApiLevel()) .addInnerClasses(DumpMainDexInputsTest.class) .addMainDexRulesFiles(newMainDexRulesPath1(), newMainDexRulesPath2()) - .addMainDexListClasses(MainDexClass1.class, MainDexClass2.class, TestClass.class) + .addMainDexKeepClassRules(MainDexClass1.class, MainDexClass2.class, TestClass.class) .addOptionsModification(options -> options.dumpInputToDirectory = dumpDir.toString()) .compile() .assertAllInfoMessagesMatch(containsString("Dumped compilation inputs to:")) @@ -136,7 +149,7 @@ .setMinApi(parameters.getApiLevel()) .addInnerClasses(DumpMainDexInputsTest.class) .addMainDexRuleFiles(newMainDexRulesPath1(), newMainDexRulesPath2()) - .addMainDexListClasses(MainDexClass1.class, MainDexClass2.class, TestClass.class) + .addMainDexKeepClassRules(MainDexClass1.class, MainDexClass2.class, TestClass.class) .addOptionsModification(options -> options.dumpInputToDirectory = dumpDir.toString()) .addKeepAllClassesRule() .allowDiagnosticMessages() @@ -168,9 +181,10 @@ assertTrue(Files.exists(unzipped.resolve("r8-version"))); assertTrue(Files.exists(unzipped.resolve("program.jar"))); assertTrue(Files.exists(unzipped.resolve("library.jar"))); - assertTrue(Files.exists(unzipped.resolve("main-dex-list.txt"))); if (checkMainDexList) { - String mainDex = new String(Files.readAllBytes(unzipped.resolve("main-dex-list.txt"))); + Path mainDexListFile = unzipped.resolve("main-dex-list.txt"); + assertTrue(Files.exists(mainDexListFile)); + String mainDex = new String(Files.readAllBytes(mainDexListFile)); List<String> mainDexLines = Arrays.stream(mainDex.split("\n")).filter(s -> !s.isEmpty()).collect(toList()); assertEquals(6, mainDexLines.size()); @@ -186,7 +200,9 @@ .collect(toList()); assertEquals(expected, mainDexLines); } else { - String mainDexRules = new String(Files.readAllBytes(unzipped.resolve("main-dex-rules.txt"))); + Path mainDexRulesFile = unzipped.resolve("main-dex-rules.txt"); + assertTrue(Files.exists(mainDexRulesFile)); + String mainDexRules = new String(Files.readAllBytes(mainDexRulesFile)); assertThat(mainDexRules, containsString(mainDexRulesForMainDexFile1AndMainDexFile2)); assertThat(mainDexRules, containsString(mainDexRulesForMainDexFile3)); }
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingClassStaticizerTest.java b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingClassStaticizerTest.java index 1e5bd5b..750c6fe 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingClassStaticizerTest.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingClassStaticizerTest.java
@@ -76,7 +76,7 @@ MethodSubject method = codeInspector.clazz(CompanionHost.class).uniqueMethodWithName(renamedMethodName); assertThat(method, isPresent()); - assertEquals("int", method.getMethod().method.proto.parameters.toString()); + assertEquals("int", method.getMethod().getReference().proto.parameters.toString()); } static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/graph/InvokeSuperTest.java b/src/test/java/com/android/tools/r8/graph/InvokeSuperTest.java index 1abfea6f..644fc9c 100644 --- a/src/test/java/com/android/tools/r8/graph/InvokeSuperTest.java +++ b/src/test/java/com/android/tools/r8/graph/InvokeSuperTest.java
@@ -60,7 +60,8 @@ String getExpectedOutput() { if (parameters.isDexRuntime()) { Version version = parameters.getRuntime().asDex().getVm().getVersion(); - if (version.isAtLeast(Version.V5_1_1) && version.isOlderThanOrEqual(Version.V6_0_1)) { + if (version.isNewerThanOrEqual(Version.V5_1_1) + && version.isOlderThanOrEqual(Version.V6_0_1)) { return UNEXPECTED_DEX_5_AND_6_OUTPUT; } }
diff --git a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java index b1d9990..06666db 100644 --- a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java +++ b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
@@ -227,7 +227,7 @@ DexField aFieldOnInterface = factory .createField(factory.createType("LInterface;"), factory.intType, "aField"); - assertEquals(aFieldOnInterface, appInfo.lookupStaticTarget(aFieldOnSubClass).field); + assertEquals(aFieldOnInterface, appInfo.lookupStaticTarget(aFieldOnSubClass).getReference()); assertEquals("42", runArt(application));
diff --git a/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java new file mode 100644 index 0000000..f989728 --- /dev/null +++ b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java
@@ -0,0 +1,111 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.graph.invokevirtual; + +import static org.junit.Assume.assumeTrue; + +import com.android.tools.r8.NoVerticalClassMerging; +import com.android.tools.r8.SingleTestRunResult; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.TestRuntime.CfVm; +import com.android.tools.r8.utils.AndroidApiLevel; +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 InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(); + } + + public InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testJvm() throws Exception { + assumeTrue(parameters.isCfRuntime()); + testForJvm() + .addInnerClasses(getClass()) + .run(parameters.getRuntime(), Main.class) + .applyIf( + parameters.isCfRuntime(CfVm.JDK11), + r -> r.assertSuccessWithOutputLines("I::foo"), + r -> r.assertFailureWithErrorThatThrows(IllegalAccessError.class)); + } + + @Test + public void testD8() throws Exception { + testForD8(parameters.getBackend()) + .addInnerClasses(getClass()) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .apply(this::assertResultIsCorrect); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepMainRule(Main.class) + .addKeepClassAndMembersRules(I.class) + .enableNoVerticalClassMergingAnnotations() + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + // TODO(b/182189123): This should have the same behavior as D8. + .assertSuccessWithOutputLines("I::foo"); + } + + public void assertResultIsCorrect(SingleTestRunResult<?> result) { + if (parameters.isCfRuntime(CfVm.JDK11) + && parameters.getApiLevel().isGreaterThan(AndroidApiLevel.M)) { + result.assertSuccessWithOutputLines("I::foo"); + return; + } + // TODO(b/152199517): Should be illegal access for DEX. + if (parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThan(AndroidApiLevel.M)) { + result.assertSuccessWithOutputLines("I::foo"); + return; + } + result.assertFailureWithErrorThatThrows(IllegalAccessError.class); + } + + @NoVerticalClassMerging + public interface I { + + default void foo() { + System.out.println("I::foo"); + } + } + + @NoVerticalClassMerging + public static class Base { + + private void foo() { + System.out.println("Base::foo"); + } + } + + public static class Sub extends Base implements I {} + + public static class Main { + + public static void main(String[] args) { + runFoo(new Sub()); + } + + private static void runFoo(I i) { + i.foo(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultTest.java b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultTest.java new file mode 100644 index 0000000..9c9926d --- /dev/null +++ b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultTest.java
@@ -0,0 +1,98 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.graph.invokevirtual; + +import static org.junit.Assume.assumeTrue; + +import com.android.tools.r8.NoVerticalClassMerging; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.utils.AndroidApiLevel; +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 InvokeVirtualPrivateBaseWithDefaultTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(); + } + + public InvokeVirtualPrivateBaseWithDefaultTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testJvm() throws Exception { + assumeTrue(parameters.isCfRuntime()); + testForJvm() + .addInnerClasses(getClass()) + .run(parameters.getRuntime(), Main.class) + .assertFailureWithErrorThatThrows(IllegalAccessError.class); + } + + @Test + public void testD8() throws Exception { + testForD8(parameters.getBackend()) + .addInnerClasses(getClass()) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .applyIf( + parameters.isCfRuntime() + || parameters.getApiLevel().isLessThanOrEqualTo(AndroidApiLevel.M), + r -> r.assertFailureWithErrorThatThrows(IllegalAccessError.class), + // TODO(b/152199517): Should be illegal access for DEX. + r -> r.assertSuccessWithOutputLines("I::foo")); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepMainRule(Main.class) + .addKeepClassAndMembersRules(I.class) + .enableNoVerticalClassMergingAnnotations() + .setMinApi(parameters.getApiLevel()) + .compile() + .run(parameters.getRuntime(), Main.class) + .applyIf( + parameters.isCfRuntime() + || parameters.getApiLevel().isLessThanOrEqualTo(AndroidApiLevel.M), + r -> r.assertFailureWithErrorThatThrows(IllegalAccessError.class), + // TODO(b/152199517): Should be illegal access for DEX. + r -> r.assertSuccessWithOutputLines("I::foo")); + } + + @NoVerticalClassMerging + public interface I { + + default void foo() { + System.out.println("I::foo"); + } + } + + @NoVerticalClassMerging + public static class Base { + + private void foo() { + System.out.println("Base::foo"); + } + } + + public static class Sub extends Base implements I {} + + public static class Main { + + public static void main(String[] args) { + new Sub().foo(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java index 51b5323..57078d1 100644 --- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java +++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
@@ -70,12 +70,13 @@ private void testVirtualLookup(DexProgramClass clazz, DexEncodedMethod method) { // Check lookup will produce the same result. - DexMethod id = method.method; + DexMethod id = method.getReference(); assertEquals( - appInfo().resolveMethodOnClass(method.method, id.holder).getSingleTarget(), method); + appInfo().resolveMethodOnClass(method.getReference(), id.holder).getSingleTarget(), method); // Check lookup targets with include method. - ResolutionResult resolutionResult = appInfo().resolveMethodOnClass(method.method, clazz); + ResolutionResult resolutionResult = + appInfo().resolveMethodOnClass(method.getReference(), clazz); AppInfoWithLiveness appInfo = null; // TODO(b/154881041): Remove or compute liveness. LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets( @@ -96,7 +97,7 @@ AppInfoWithLiveness appInfo = null; // TODO(b/154881041): Remove or compute liveness. LookupResultSuccess lookupResult = appInfo() - .resolveMethodOnInterface(clazz, method.method) + .resolveMethodOnInterface(clazz, method.getReference()) .lookupVirtualDispatchTargets(clazz, appInfo(), appInfo, dexReference -> false) .asLookupResultSuccess(); assertNotNull(lookupResult);
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java index 024dd38..ec665d3 100644 --- a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java +++ b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
@@ -140,7 +140,7 @@ private DexEncodedField uniqueFieldByName(DexProgramClass clazz, String name) { DexEncodedField result = null; for (DexEncodedField field : clazz.fields()) { - if (field.field.name.toSourceString().equals(name)) { + if (field.getReference().name.toSourceString().equals(name)) { assertNull(result); result = field; }
diff --git a/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java b/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java index 009d4e3d..36acfe9 100644 --- a/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java +++ b/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java
@@ -137,7 +137,7 @@ private Node findNode(Iterable<Node> nodes, String name) { for (Node n : nodes) { - if (n.getMethod().method.name.toString().equals(name)) { + if (n.getMethod().getReference().name.toString().equals(name)) { return n; } } @@ -147,7 +147,7 @@ private ProgramMethod findMethod(String name) { for (DexProgramClass clazz : appView.appInfo().classes()) { for (DexEncodedMethod method : clazz.methods()) { - if (method.method.name.toString().equals(name)) { + if (method.getReference().name.toString().equals(name)) { return new ProgramMethod(clazz, method); } }
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java index a3bd157..bc84108 100644 --- a/src/test/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java +++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java
@@ -62,4 +62,15 @@ CharSequence s, int beginIndex, int endIndex, int radix) throws NumberFormatException { return Integer.parseInt(s.subSequence(beginIndex, endIndex).toString(), radix); } + + public static int parseIntSubsequenceWithRadixDalvik( + CharSequence s, int beginIndex, int endIndex, int radix) throws NumberFormatException { + // Dalvik (API level 19 and below) does not support a '+' prefix. + if (endIndex - beginIndex >= 2 + && s.charAt(beginIndex) == '+' + && Character.digit(s.charAt(beginIndex + 1), radix) >= 0) { + beginIndex++; + } + return Integer.parseInt(s.subSequence(beginIndex, endIndex).toString(), radix); + } }
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/LongMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/LongMethods.java index 65a60ef..089fa86 100644 --- a/src/test/java/com/android/tools/r8/ir/desugar/backports/LongMethods.java +++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/LongMethods.java
@@ -15,6 +15,17 @@ return Long.parseLong(s.subSequence(beginIndex, endIndex).toString(), radix); } + public static long parseLongSubsequenceWithRadixDalvik( + CharSequence s, int beginIndex, int endIndex, int radix) { + // Dalvik (API level 19 and below) does not support a '+' prefix. + if (endIndex - beginIndex >= 2 + && s.charAt(beginIndex) == '+' + && Character.digit(s.charAt(beginIndex + 1), radix) >= 0) { + beginIndex++; + } + return Long.parseLong(s.subSequence(beginIndex, endIndex).toString(), radix); + } + public static long divideUnsigned(long dividend, long divisor) { // This implementation is adapted from Guava's UnsignedLongs.java and Longs.java.
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java index 7049089..aad2f6f 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
@@ -276,7 +276,7 @@ for (int i = 0; i < 3; ++i) { MethodSubject markerSubject = clazz.method("void", "marker" + i, Collections.emptyList()); assertTrue(markerSubject.isPresent()); - markers[i] = markerSubject.getMethod().method; + markers[i] = markerSubject.getMethod().getReference(); } // Count invokes to callee between markers. @@ -290,7 +290,7 @@ DexMethod target = ((InvokeInstructionSubject) instruction).invokedMethod(); - if (target == callee.getMethod().method) { + if (target == callee.getMethod().getReference()) { assertTrue(phase == 0 || phase == 1); ++counters[phase]; continue;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/EnumCanonicalizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/EnumCanonicalizationTest.java index 589fa3f..709a44b 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/EnumCanonicalizationTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/EnumCanonicalizationTest.java
@@ -73,7 +73,7 @@ .streamInstructions() .filter(InstructionSubject::isStaticGet) .map(InstructionSubject::getField) - .filter(enumFieldSubject.getField().field::equals) + .filter(enumFieldSubject.getField().getReference()::equals) .count()); assertEquals( 1, @@ -81,7 +81,9 @@ .streamInstructions() .filter(InstructionSubject::isStaticGet) .map(InstructionSubject::getField) - .filter(enumWithClassInitializationSideEffectsFieldSubject.getField().field::equals) + .filter( + enumWithClassInitializationSideEffectsFieldSubject.getField().getReference() + ::equals) .count()); }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PackagePrivateOverrideDeVirtualizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PackagePrivateOverrideDeVirtualizerTest.java new file mode 100644 index 0000000..b3ca988 --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PackagePrivateOverrideDeVirtualizerTest.java
@@ -0,0 +1,113 @@ +// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.ir.optimize.devirtualize; + +import com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.NoVerticalClassMerging; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.TestRunResult; +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 PackagePrivateOverrideDeVirtualizerTest extends TestBase { + + private final TestParameters parameters; + private final String[] EXPECTED = new String[] {"SubViewModel.clear()", "ViewModel.clear()"}; + private final String[] EXPECTED_DALVIK = + new String[] {"SubViewModel.clear()", "SubViewModel.clear()"}; + private final String NEW_DESCRIPTOR = "Lfoo/bar/baz/SubViewModel;"; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public PackagePrivateOverrideDeVirtualizerTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testRuntime() throws Exception { + testForRuntime(parameters) + .addProgramClasses(ViewModel.class) + .addProgramClassFileData( + getSubViewModelInAnotherPackage(), getRewrittenSubViewModelInMain()) + .run(parameters.getRuntime(), Main.class) + .apply(this::assertSuccessOutput); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addProgramClasses(ViewModel.class) + .addProgramClassFileData( + getSubViewModelInAnotherPackage(), getRewrittenSubViewModelInMain()) + .addKeepMainRule(Main.class) + .setMinApi(parameters.getApiLevel()) + .enableInliningAnnotations() + .enableNoVerticalClassMergingAnnotations() + .enableNeverClassInliningAnnotations() + .run(parameters.getRuntime(), Main.class) + // TODO(b/182185057): This should be EXPECTED. + .assertSuccessWithOutputLines(EXPECTED_DALVIK); + } + + private byte[] getSubViewModelInAnotherPackage() throws Exception { + return transformer(SubViewModel.class).setClassDescriptor(NEW_DESCRIPTOR).transform(); + } + + private byte[] getRewrittenSubViewModelInMain() throws Exception { + return transformer(Main.class) + .replaceClassDescriptorInMethodInstructions(descriptor(SubViewModel.class), NEW_DESCRIPTOR) + .transform(); + } + + private void assertSuccessOutput(TestRunResult<?> result) { + if (parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isDalvik()) { + result.assertSuccessWithOutputLines(EXPECTED_DALVIK); + } else { + result.assertSuccessWithOutputLines(EXPECTED); + } + } + + @SuppressWarnings("override") /* after changing the package the clear method is not overridden */ + @NoVerticalClassMerging + public static class ViewModel { + + @NeverInline + void clear() { + System.out.println("ViewModel.clear()"); + } + } + + @NeverClassInline + @SuppressWarnings("override") /* after changing the package the clear method is not overridden */ + public static class /* foo.bar.baz. */ SubViewModel extends ViewModel { + + @NeverInline + public void clear() { + System.out.println("SubViewModel.clear()"); + } + + public void callBridge() { + clear(); + } + } + + public static class Main { + + public static void main(String[] args) { + SubViewModel viewModel = new SubViewModel(); + viewModel.callBridge(); + ((ViewModel) viewModel).clear(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/MemberValuePropagationWithClassInitializationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/MemberValuePropagationWithClassInitializationTest.java index 50e52e2..fb3d7e4 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/MemberValuePropagationWithClassInitializationTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/MemberValuePropagationWithClassInitializationTest.java
@@ -84,7 +84,7 @@ mainMethodSubject .streamInstructions() .filter(InstructionSubject::isStaticGet) - .anyMatch(x -> x.getField() == clinitFieldSubject.getField().field)); + .anyMatch(x -> x.getField() == clinitFieldSubject.getField().getReference())); } static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantFinalInstanceFieldLoadAfterStoreTest.java b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantFinalInstanceFieldLoadAfterStoreTest.java index 329e574..cad2c50 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantFinalInstanceFieldLoadAfterStoreTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantFinalInstanceFieldLoadAfterStoreTest.java
@@ -10,7 +10,6 @@ import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; -import com.android.tools.r8.ir.optimize.redundantfieldloadelimination.RedundantFinalStaticFieldLoadAfterStoreTest.A; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; import com.android.tools.r8.utils.codeinspector.FieldSubject; @@ -80,7 +79,7 @@ .streamInstructions() .filter(InstructionSubject::isInstanceGet) .map(InstructionSubject::getField) - .filter(fieldSubject.getField().field::equals) + .filter(fieldSubject.getField().getReference()::equals) .count(); }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantFinalStaticFieldLoadAfterStoreTest.java b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantFinalStaticFieldLoadAfterStoreTest.java index 2b910f5..701c43f 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantFinalStaticFieldLoadAfterStoreTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantFinalStaticFieldLoadAfterStoreTest.java
@@ -77,7 +77,7 @@ .streamInstructions() .filter(InstructionSubject::isStaticGet) .map(InstructionSubject::getField) - .filter(fieldSubject.getField().field::equals) + .filter(fieldSubject.getField().getReference()::equals) .count(); }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java index 6e91c38..d268888 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
@@ -345,7 +345,7 @@ assertThat(clazz, isPresent()); return Streams.stream(clazz.getDexProgramClass().methods()) .filter(method -> !method.isStatic()) - .map(method -> method.method.toSourceString()) + .map(method -> method.getReference().toSourceString()) .sorted() .collect(Collectors.toList()); }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java index b254b43..0125189 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java
@@ -64,7 +64,7 @@ MethodSubject createStaticMethodSubject = factoryClassSubject.uniqueMethodWithName("createStatic"); assertThat(createStaticMethodSubject, isPresent()); - assertEquals(1, createStaticMethodSubject.getMethod().method.proto.parameters.size()); + assertEquals(1, createStaticMethodSubject.getMethod().getReference().proto.parameters.size()); for (int i = 1; i <= 3; ++i) { String createStaticWithUnusedMethodName = "createStaticWithUnused" + i; @@ -72,7 +72,7 @@ factoryClassSubject.uniqueMethodWithName(createStaticWithUnusedMethodName); assertThat(createStaticWithUnusedMethodSubject, isPresent()); - DexMethod method = createStaticWithUnusedMethodSubject.getMethod().method; + DexMethod method = createStaticWithUnusedMethodSubject.getMethod().getReference(); assertEquals(1, method.proto.parameters.size()); assertEquals("java.lang.String", method.proto.parameters.toString()); } @@ -81,7 +81,7 @@ factoryClassSubject.uniqueMethodWithName("createStaticWithUnused4"); assertThat(createStaticWithUnusedMethodSubject, isPresent()); - DexMethod method = createStaticWithUnusedMethodSubject.getMethod().method; + DexMethod method = createStaticWithUnusedMethodSubject.getMethod().getReference(); assertEquals(3, method.proto.parameters.size()); assertEquals( "java.lang.String java.lang.String java.lang.String", method.proto.parameters.toString());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java index 0de94c9..8dc29fb 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java
@@ -81,7 +81,7 @@ assertEquals(2, aClassSubject.allMethods(FoundMethodSubject::isVirtual).size()); String name = null; for (FoundMethodSubject m : aClassSubject.allMethods(FoundMethodSubject::isVirtual)) { - assertEquals(1, m.getMethod().method.proto.parameters.size()); + assertEquals(1, m.getMethod().getReference().proto.parameters.size()); if (name == null) { name = m.getFinalName(); } else {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java index c6dfe83..2e3904a 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java
@@ -95,7 +95,7 @@ // TODO(b/131735725): Should also remove arguments from the virtual methods. if (keepUninstantiatedArguments || methodSubject.getOriginalName().contains("Virtual")) { - assertEquals(3, methodSubject.getMethod().method.proto.parameters.size()); + assertEquals(3, methodSubject.getMethod().getReference().proto.parameters.size()); assertEquals(3, methodSubject.getMethod().parameterAnnotationsList.size()); for (int i = 0; i < 3; ++i) { @@ -115,7 +115,7 @@ } } } else { - assertEquals(2, methodSubject.getMethod().method.proto.parameters.size()); + assertEquals(2, methodSubject.getMethod().getReference().proto.parameters.size()); assertEquals(2, methodSubject.getMethod().parameterAnnotationsList.size()); for (int i = 0; i < 2; ++i) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java index 0ac4efc..5e5345a 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
@@ -63,16 +63,16 @@ MethodSubject createStaticMethodSubject = factoryClassSubject.uniqueMethodWithName("createStatic"); assertThat(createStaticMethodSubject, isPresent()); - assertTrue(createStaticMethodSubject.getMethod().method.proto.returnType.isVoidType()); + assertTrue(createStaticMethodSubject.getMethod().getReference().proto.returnType.isVoidType()); MethodSubject createVirtualMethodSubject = factoryClassSubject.uniqueMethodWithName("createVirtual"); assertThat(createVirtualMethodSubject, isPresent()); - assertTrue(createVirtualMethodSubject.getMethod().method.proto.returnType.isVoidType()); + assertTrue(createVirtualMethodSubject.getMethod().getReference().proto.returnType.isVoidType()); createVirtualMethodSubject = inspector.clazz(SubFactory.class).uniqueMethodWithName("createVirtual"); assertThat(createVirtualMethodSubject, isPresent()); - assertTrue(createVirtualMethodSubject.getMethod().method.proto.returnType.isVoidType()); + assertTrue(createVirtualMethodSubject.getMethod().getReference().proto.returnType.isVoidType()); ClassSubject subSubFactoryClassSubject = inspector.clazz(SubSubFactory.class); assertThat(subSubFactoryClassSubject.method("void", "createVirtual"), isPresent());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java index 45d858d..14efc77 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java
@@ -65,10 +65,10 @@ if (minification) { assertEquals("a", methodSubject.getFinalName()); - assertEquals(0, methodSubject.getMethod().method.proto.parameters.size()); + assertEquals(0, methodSubject.getMethod().getReference().proto.parameters.size()); } else { assertEquals("toString1", methodSubject.getFinalName()); - assertEquals(0, methodSubject.getMethod().method.proto.parameters.size()); + assertEquals(0, methodSubject.getMethod().getReference().proto.parameters.size()); } }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java index 073c3b4..b7ddd9e 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java
@@ -79,7 +79,7 @@ assertEquals(2, aClassSubject.allMethods(FoundMethodSubject::isVirtual).size()); String name = null; for (FoundMethodSubject m : aClassSubject.allMethods(FoundMethodSubject::isVirtual)) { - assertEquals(1, m.getMethod().method.proto.parameters.size()); + assertEquals(1, m.getMethod().getReference().proto.parameters.size()); if (name == null) { name = m.getFinalName(); } else {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java index af6296b..138f0a9 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java
@@ -58,8 +58,8 @@ List<FoundMethodSubject> methods = i.clazz(Main.class).allMethods(); assertEquals(9, methods.size()); for (FoundMethodSubject method : methods) { - if (!method.getMethod().method.name.toString().equals("main")) { - assertEquals(0, method.getMethod().method.getArity()); + if (!method.getMethod().getReference().name.toString().equals("main")) { + assertEquals(0, method.getMethod().getReference().getArity()); } } }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsTest.java index bd1b805..955c5d4 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsTest.java
@@ -91,7 +91,7 @@ assertThat(methodSubject, isPresent()); if (keepUnusedArguments) { - assertEquals(3, methodSubject.getMethod().method.proto.parameters.size()); + assertEquals(3, methodSubject.getMethod().getReference().proto.parameters.size()); assertEquals(3, methodSubject.getMethod().parameterAnnotationsList.size()); for (int i = 0; i < 3; ++i) { @@ -109,7 +109,7 @@ } } } else { - assertEquals(2, methodSubject.getMethod().method.proto.parameters.size()); + assertEquals(2, methodSubject.getMethod().getReference().proto.parameters.size()); assertEquals(2, methodSubject.getMethod().parameterAnnotationsList.size()); for (int i = 0; i < 2; ++i) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java index 7456d35..281db3e 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
@@ -63,7 +63,8 @@ MethodSubject methodSubject = classSubject.uniqueMethodWithName("greeting"); assertThat(methodSubject, isPresent()); - assertEquals("java.lang.String", methodSubject.getMethod().method.proto.parameters.toString()); + assertEquals( + "java.lang.String", methodSubject.getMethod().getReference().proto.parameters.toString()); } static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java index 2c7fe55..1137a01 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
@@ -85,7 +85,7 @@ MethodSubject methodB1Subject = bClassSubject.allMethods().stream().filter(FoundMethodSubject::isStatic).findFirst().get(); assertThat(methodB1Subject, isPresent()); - assertEquals(0, methodB1Subject.getMethod().method.proto.parameters.size()); + assertEquals(0, methodB1Subject.getMethod().getReference().proto.parameters.size()); // TODO(b/129933280): Determine if we should use member pool collection for unused argument // removal for private and static methods. @@ -97,7 +97,7 @@ MethodSubject methodB2Subject = bClassSubject.allMethods().stream().filter(FoundMethodSubject::isVirtual).findFirst().get(); assertThat(methodB2Subject, isPresent()); - assertEquals(0, methodB2Subject.getMethod().method.proto.parameters.size()); + assertEquals(0, methodB2Subject.getMethod().getReference().proto.parameters.size()); // Verify that the virtual method B.method2() does not collide with a method in A. assertNotEquals(methodB2Subject.getFinalName(), methodA1Subject.getFinalName());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java index ea67170..c890e97 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java
@@ -59,7 +59,7 @@ MethodSubject methodSubject = classSubject.uniqueMethodWithName("<init>"); assertThat(methodSubject, isPresent()); - assertTrue(methodSubject.getMethod().method.proto.parameters.isEmpty()); + assertTrue(methodSubject.getMethod().getReference().proto.parameters.isEmpty()); assertThat(inspector.clazz(B.class), not(isPresent())); assertThat(inspector.clazz(C.class), not(isPresent()));
diff --git a/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java b/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java index 23c4628..7f41f05 100644 --- a/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java +++ b/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
@@ -213,9 +213,14 @@ String returnType, String... lines) { StringBuilder builder = new StringBuilder(); - builder.append(".method ").append(access).append(" ").append(name) - .append(StringUtils.join(argumentTypes, "", BraceType.PARENS)) - .append(returnType).append("\n"); + builder + .append(".method ") + .append(access) + .append(" ") + .append(name) + .append(StringUtils.join("", argumentTypes, BraceType.PARENS)) + .append(returnType) + .append("\n"); for (String line : lines) { builder.append(line).append("\n"); } @@ -382,7 +387,7 @@ } builder .append(name) - .append(StringUtils.join(argumentTypes, "", BraceType.PARENS)) + .append(StringUtils.join("", argumentTypes, BraceType.PARENS)) .append(returnType) .append(System.lineSeparator()); builder.append(".limit locals ").append(localsLimit).append(System.lineSeparator());
diff --git a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java index ab2d643..73f7a6f 100644 --- a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java +++ b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
@@ -219,7 +219,7 @@ List<String> args = new ArrayList<>(); args.add("--output=" + dex.toString()); args.add(classes.toString()); - System.out.println("running: dx " + StringUtils.join(args, " ")); + System.out.println("running: dx " + StringUtils.join(" ", args)); return ToolHelper.runDX(args.toArray(new String[args.size()])); }
diff --git a/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java b/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java index d21bd3a..a831fb0 100644 --- a/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java +++ b/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java
@@ -70,7 +70,7 @@ } static boolean isAndroidKOrAbove(DexVm dexVm, Tool tool) { - return dexVm.getVersion().isAtLeast(Version.V4_4_4); + return dexVm.getVersion().isNewerThanOrEqual(Version.V4_4_4); } static boolean isAndroidLOrAbove(DexVm dexVm, Tool tool) {
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java index b76eaa0..872b5f0 100644 --- a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
@@ -129,7 +129,7 @@ MethodSubject method = main.uniqueMethodWithName(methodName); assertThat(method, isPresent()); - int arity = method.getMethod().method.getArity(); + int arity = method.getMethod().getReference().getArity(); // One from the method's own argument, if any, and // Two from Array utils, `contains` and `indexOf`, if inlined with access relaxation. assertEquals(
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java index 4db441f..19458e2 100644 --- a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java
@@ -52,7 +52,7 @@ MethodSubject invoke = classSubject.uniqueMethodWithName("invoke"); assertThat(invoke, isPresent()); - assertEquals(2, invoke.getMethod().method.proto.parameters.size()); + assertEquals(2, invoke.getMethod().getReference().proto.parameters.size()); } })); } @@ -68,7 +68,7 @@ if (classSubject.getOriginalDescriptor().contains("$js")) { MethodSubject get = classSubject.uniqueMethodWithName("get"); assertThat(get, isPresent()); - assertEquals(3, get.getMethod().method.proto.parameters.size()); + assertEquals(3, get.getMethod().getReference().proto.parameters.size()); } })); }
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexDevirtualizerTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexDevirtualizerTest.java index 6cb7ab4..ad0cf84 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexDevirtualizerTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexDevirtualizerTest.java
@@ -79,13 +79,16 @@ }); } + // TODO(b/181858113): This test is likely obsolete once main-dex-list support is removed. @Test public void testMainDexClasses() throws Exception { assumeTrue(parameters.isDexRuntime()); assumeTrue(parameters.getDexRuntimeVersion().isDalvik()); runTest( r8FullTestBuilder -> - r8FullTestBuilder.addMainDexListClasses(I.class, Provider.class, Main.class), + r8FullTestBuilder + .addMainDexListClasses(I.class, Provider.class, Main.class) + .allowDiagnosticWarningMessages(), this::inspect); } @@ -94,7 +97,7 @@ assumeTrue(parameters.isDexRuntime()); assumeTrue(parameters.getDexRuntimeVersion().isDalvik()); runTest( - r8FullTestBuilder -> r8FullTestBuilder.addMainDexClassRules(Main.class, I.class), + r8FullTestBuilder -> r8FullTestBuilder.addMainDexKeepClassRules(Main.class, I.class), this::inspect); }
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningSpuriousRootTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningSpuriousRootTest.java index 5f21fee..3290031 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningSpuriousRootTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningSpuriousRootTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.maindexlist; +import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType; import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static org.hamcrest.MatcherAssert.assertThat; @@ -15,6 +16,7 @@ import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.errors.UnsupportedMainDexListUsageDiagnostic; import com.android.tools.r8.references.ClassReference; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; @@ -59,6 +61,7 @@ this.parameters = parameters; } + // TODO(b/181858113): This test is likely obsolete once main-dex-list support is removed. @Test public void test() throws Exception { // The generated main dex list should contain Main (which is a root) and A (which is a direct @@ -82,7 +85,13 @@ .enableNoHorizontalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) .noMinification() - .compile(); + .allowDiagnosticMessages() + .compileWithExpectedDiagnostics( + diagnostics -> + diagnostics + .assertOnlyWarnings() + .assertWarningsMatch( + diagnosticType(UnsupportedMainDexListUsageDiagnostic.class))); CodeInspector inspector = compileResult.inspector(); ClassSubject mainClassSubject = inspector.clazz(Main.class); assertThat(mainClassSubject, isPresent());
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningTest.java index 98ec426..013fdd3 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.maindexlist; +import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType; import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static org.hamcrest.MatcherAssert.assertThat; @@ -16,6 +17,7 @@ import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.errors.UnsupportedMainDexListUsageDiagnostic; import com.android.tools.r8.references.ClassReference; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; @@ -61,6 +63,7 @@ this.parameters = parameters; } + // TODO(b/181858113): This test is likely obsolete once main-dex-list support is removed. @Test public void test() throws Exception { // The generated main dex list should contain Main (which is a root) and A (which is a direct @@ -80,7 +83,13 @@ .enableNoHorizontalClassMergingAnnotations() .enableNoHorizontalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .compile(); + .allowDiagnosticMessages() + .compileWithExpectedDiagnostics( + diagnostics -> + diagnostics + .assertOnlyWarnings() + .assertWarningsMatch( + diagnosticType(UnsupportedMainDexListUsageDiagnostic.class))); CodeInspector inspector = compileResult.inspector(); ClassSubject mainClassSubject = inspector.clazz(Main.class);
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningWithTracingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningWithTracingTest.java index f5971f9..bb3b81c 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningWithTracingTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningWithTracingTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.maindexlist; +import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType; import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static org.hamcrest.MatcherAssert.assertThat; @@ -16,6 +17,7 @@ import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.errors.UnsupportedMainDexListUsageDiagnostic; import com.android.tools.r8.references.ClassReference; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; @@ -61,6 +63,7 @@ this.parameters = parameters; } + // TODO(b/181858113): This test is likely obsolete once main-dex-list support is removed. @Test public void test() throws Exception { // The generated main dex list should contain Main (which is a root) and A (which is a direct @@ -84,7 +87,13 @@ .enableNoHorizontalClassMergingAnnotations() .noMinification() .setMinApi(parameters.getApiLevel()) - .compile(); + .allowDiagnosticMessages() + .compileWithExpectedDiagnostics( + diagnostics -> + diagnostics + .assertOnlyWarnings() + .assertWarningsMatch( + diagnosticType(UnsupportedMainDexListUsageDiagnostic.class))); CodeInspector inspector = compileResult.inspector(); ClassSubject mainClassSubject = inspector.clazz(Main.class);
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainHorizontalMergingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainHorizontalMergingTest.java index c2c96ec..4d59d9b 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainHorizontalMergingTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainHorizontalMergingTest.java
@@ -65,6 +65,7 @@ this.parameters = parameters; } + // TODO(b/181858113): This test is likely obsolete once main-dex-list support is removed. @Test public void testMainDexList() throws Exception { assertEquals(3, mainDexList.size()); @@ -73,7 +74,9 @@ assertTrue(mainDexReferences.contains(A.class.getTypeName())); assertTrue(mainDexReferences.contains(B.class.getTypeName())); assertTrue(mainDexReferences.contains(Main.class.getTypeName())); - runTest(builder -> builder.addMainDexListClassReferences(mainDexList)); + runTest( + builder -> + builder.addMainDexListClassReferences(mainDexList).allowDiagnosticWarningMessages()); } @Test
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainVerticalMergingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainVerticalMergingTest.java index ec50d1e..480abb7 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainVerticalMergingTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainVerticalMergingTest.java
@@ -65,6 +65,7 @@ this.parameters = parameters; } + // TODO(b/181858113): This test is likely obsolete once main-dex-list support is removed. @Test public void testMainDexList() throws Exception { assertEquals(3, mainDexList.size()); @@ -73,7 +74,9 @@ assertTrue(mainDexReferences.contains(A.class.getTypeName())); assertTrue(mainDexReferences.contains(B.class.getTypeName())); assertTrue(mainDexReferences.contains(Main.class.getTypeName())); - runTest(builder -> builder.addMainDexListClassReferences(mainDexList)); + runTest( + builder -> + builder.addMainDexListClassReferences(mainDexList).allowDiagnosticWarningMessages()); } @Test
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListInliningTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListInliningTest.java index 09df9d4..731d0ec 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListInliningTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListInliningTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.maindexlist; +import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertFalse; @@ -14,6 +15,7 @@ import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.errors.UnsupportedMainDexListUsageDiagnostic; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; import org.junit.Test; @@ -37,6 +39,7 @@ this.parameters = parameters; } + // TODO(b/181858113): This test should be converted to a main-dex-rules test. @Test public void test() throws Exception { R8TestCompileResult compileResult = @@ -47,7 +50,13 @@ .collectMainDexClasses() .enableNoHorizontalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .compile(); + .allowDiagnosticMessages() + .compileWithExpectedDiagnostics( + diagnostics -> + diagnostics + .assertOnlyWarnings() + .assertWarningsMatch( + diagnosticType(UnsupportedMainDexListUsageDiagnostic.class))); CodeInspector inspector = compileResult.inspector();
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListNoDirectDependenciesTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListNoDirectDependenciesTest.java index 8f5d997..e72cc3e 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListNoDirectDependenciesTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListNoDirectDependenciesTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.maindexlist; +import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -11,6 +12,7 @@ import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.errors.UnsupportedMainDexListUsageDiagnostic; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; import org.junit.Test; @@ -34,17 +36,24 @@ this.parameters = parameters; } + // TODO(b/181858113): This test is likely obsolete once main-dex-list support is removed. @Test public void test() throws Exception { R8TestCompileResult compileResult = testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addMainDexListClasses(A.class) - .addMainDexClassRules(B.class) + .addMainDexKeepClassRules(B.class) .collectMainDexClasses() .noTreeShaking() .setMinApi(parameters.getApiLevel()) - .compile(); + .allowDiagnosticMessages() + .compileWithExpectedDiagnostics( + diagnostics -> + diagnostics + .assertOnlyWarnings() + .assertWarningsMatch( + diagnosticType(UnsupportedMainDexListUsageDiagnostic.class))); CodeInspector inspector = compileResult.inspector();
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexPrunedReferenceTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexPrunedReferenceTest.java index e2d7dd2..c10a7a6 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexPrunedReferenceTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexPrunedReferenceTest.java
@@ -48,11 +48,12 @@ testMainDex(builder -> {}, Assert::assertNull); } + // TODO(b/181858113): This test is likely obsolete once main-dex-list support is removed. @Test public void testMainDexClassesList() throws Exception { assumeTrue(parameters.getDexRuntimeVersion().isDalvik()); testMainDex( - builder -> builder.addMainDexListClasses(Main.class), + builder -> builder.addMainDexListClasses(Main.class).allowDiagnosticWarningMessages(), mainDexClasses -> assertEquals(ImmutableSet.of(Main.class.getTypeName()), mainDexClasses)); }
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java index 8252f4d..16dc8db 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java
@@ -3,6 +3,9 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.maindexlist; +import static com.android.tools.r8.DiagnosticsMatcher.diagnosticOrigin; +import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType; +import static org.hamcrest.CoreMatchers.allOf; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; @@ -11,11 +14,17 @@ import com.android.tools.r8.R8TestCompileResult; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestCompileResult; +import com.android.tools.r8.TestDiagnosticMessages; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.errors.UnsupportedMainDexListUsageDiagnostic; +import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.origin.PathOrigin; import com.android.tools.r8.synthesis.SyntheticItemsTestUtils; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.AndroidApp; +import com.android.tools.r8.utils.FileUtils; import com.android.tools.r8.utils.StringUtils; import com.android.tools.r8.utils.codeinspector.CodeInspector; import java.nio.file.Files; @@ -81,23 +90,67 @@ checkCompilationResult(compileResult); } + @Test + public void testSupportedMainDexListD8() throws Exception { + assumeTrue(parameters.isDexRuntime()); + // It remains a supported mode to first compile to DEX and then use tracing on the compiled + // output. Neither the compilation, the trace or the merge should issue any diagnostics. + Path dexed = + testForD8() + .addInnerClasses(MainDexWithSynthesizedClassesTest.class) + .setMinApi(parameters.getApiLevel()) + .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertNoMessages) + .writeToZip(); + + Path mainDexFile = temp.newFile("maindex.list").toPath(); + testForMainDexListGenerator() + .addLibraryFiles(ToolHelper.getFirstSupportedAndroidJar(parameters.getApiLevel())) + .addProgramFiles(dexed) + .addMainDexRules("-keep class " + typeName(TestClass.class) + "{ *; }") + .setMainDexListOutputPath(mainDexFile) + .run(); + + D8TestCompileResult compileResult = + testForD8() + .addProgramFiles(dexed) + .addMainDexListFiles(mainDexFile) + .setMinApi(parameters.getApiLevel()) + .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertNoMessages); + checkCompilationResult(compileResult); + } + /** * This test checks for maintained support of including synthetics from main-dex-list entries in * the main-dex file. This test simulates that the tracing done at the class-file level has * determined that TestClass and A are both traced. Thus the synthetic lambda from A will be * included in the main-dex file. * - * <p>TODO(b/181858113): Remove once deprecated main-dex-list is removed. + * <p>TODO(b/181858113): Update to assert an error is raised once deprecated period is over. */ @Test public void testDeprecatedSyntheticsFromMainDexListD8() throws Exception { assumeTrue(parameters.isDexRuntime()); + Path mainDexFile = temp.newFile("maindex.list").toPath(); + FileUtils.writeTextFile(mainDexFile, binaryName(A.class) + ".class"); D8TestCompileResult compileResult = testForD8() .addInnerClasses(MainDexWithSynthesizedClassesTest.class) - .addMainDexListClasses(TestClass.class, A.class) + .addMainDexListClasses(TestClass.class) + .addMainDexListFiles(mainDexFile) .setMinApi(parameters.getApiLevel()) - .compile(); + .compileWithExpectedDiagnostics( + diagnostics -> + diagnostics + .assertOnlyWarnings() + .assertWarningsMatch( + // The "classes" addition has no origin. + allOf( + diagnosticType(UnsupportedMainDexListUsageDiagnostic.class), + diagnosticOrigin(Origin.unknown())), + // The "file" addition must have the file origin. + allOf( + diagnosticType(UnsupportedMainDexListUsageDiagnostic.class), + diagnosticOrigin(new PathOrigin(mainDexFile))))); checkCompilationResult(compileResult); } @@ -112,15 +165,31 @@ @Test public void testDeprecatedSyntheticsFromMainDexListR8() throws Exception { assumeTrue(parameters.isDexRuntime()); + Path mainDexFile = temp.newFile("maindex.list").toPath(); + FileUtils.writeTextFile(mainDexFile, binaryName(A.class) + ".class"); R8TestCompileResult compileResult = testForR8(parameters.getBackend()) .addInnerClasses(MainDexWithSynthesizedClassesTest.class) .setMinApi(parameters.getApiLevel()) .addOptionsModification(o -> o.minimalMainDex = true) - .addMainDexListClasses(TestClass.class, A.class) + .addMainDexListClasses(TestClass.class) + .addMainDexListFiles(mainDexFile) .noMinification() .noTreeShaking() - .compile(); + .allowDiagnosticWarningMessages() + .compileWithExpectedDiagnostics( + diagnostics -> + diagnostics + .assertOnlyWarnings() + .assertWarningsMatch( + // The "classes" addition has no origin. + allOf( + diagnosticType(UnsupportedMainDexListUsageDiagnostic.class), + diagnosticOrigin(Origin.unknown())), + // The "file" addition must have the file origin. + allOf( + diagnosticType(UnsupportedMainDexListUsageDiagnostic.class), + diagnosticOrigin(new PathOrigin(mainDexFile))))); checkCompilationResult(compileResult, compileResult.app); } @@ -128,7 +197,7 @@ checkCompilationResult(compileResult, compileResult.app); } - private void checkCompilationResult(TestCompileResult compileResult, AndroidApp app) + private void checkCompilationResult(TestCompileResult<?, ?> compileResult, AndroidApp app) throws Exception { if (parameters.getRuntime().asDex().getMinApiLevel().getLevel() < nativeMultiDexLevel.getLevel()) {
diff --git a/src/test/java/com/android/tools/r8/maindexlist/warnings/MainDexWarningsTest.java b/src/test/java/com/android/tools/r8/maindexlist/warnings/MainDexWarningsTest.java index 22bad85..19e75b3 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/warnings/MainDexWarningsTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/warnings/MainDexWarningsTest.java
@@ -56,7 +56,7 @@ .addProgramClasses(testClasses) .addKeepMainRule(mainClass) // Include main dex rule for class Static. - .addMainDexClassRules(Main.class, Static.class) + .addMainDexKeepClassRules(Main.class, Static.class) .enableForceInliningAnnotations() .setMinApi(parameters.getApiLevel()) .compile() @@ -93,7 +93,7 @@ // Include explicit main dex entry for class Static. .addMainDexListClasses(Main.class, Static.class) // Include main dex rule for class Static2. - .addMainDexClassRules(Static2.class) + .addMainDexKeepClassRules(Static2.class) .addDontWarn(Static.class) .allowDiagnosticWarningMessages() .enableForceInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingClassPathInterfaceInheritTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingClassPathInterfaceInheritTest.java new file mode 100644 index 0000000..5270eab --- /dev/null +++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingClassPathInterfaceInheritTest.java
@@ -0,0 +1,84 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.naming.applymapping; + +import com.android.tools.r8.R8TestCompileResult; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestShrinkerBuilder; +import com.android.tools.r8.utils.BooleanUtils; +import java.nio.file.Path; +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) +// This is a reproduction of b/181887416. +public class ApplyMappingClassPathInterfaceInheritTest extends TestBase { + + private final TestParameters parameters; + private final boolean minifyLibrary; + + @Parameters(name = "{0}, minifyLibrary: {1}") + public static List<Object[]> data() { + return buildParameters( + getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values()); + } + + public ApplyMappingClassPathInterfaceInheritTest( + TestParameters parameters, boolean minifyLibrary) { + this.parameters = parameters; + this.minifyLibrary = minifyLibrary; + } + + @Test + public void testApplyMapping() throws Exception { + R8TestCompileResult libraryResult = + testForR8(parameters.getBackend()) + .addLibraryClasses(LibI.class) + .addDefaultRuntimeLibrary(parameters) + .addProgramClasses(ClassPathI.class) + .applyIf( + minifyLibrary, + TestShrinkerBuilder::addKeepAllClassesRuleWithAllowObfuscation, + TestShrinkerBuilder::addKeepAllClassesRule) + .setMinApi(parameters.getApiLevel()) + .compile(); + Path libraryJar = libraryResult.writeToZip(); + testForR8(parameters.getBackend()) + .addLibraryClasses(LibI.class) + .addDefaultRuntimeLibrary(parameters) + .addClasspathClasses(ClassPathI.class) + .addProgramClasses(Main.class) + .addKeepAllClassesRule() + .addApplyMapping(libraryResult.getProguardMap()) + .setMinApi(parameters.getApiLevel()) + .compile() + .addRunClasspathClasses(LibI.class) + .addRunClasspathFiles(libraryJar) + .run(parameters.getRuntime(), Main.class) + .applyIf( + minifyLibrary, + r -> r.assertSuccessWithOutputLines("a.a"), + r -> r.assertSuccessWithOutputLines(ClassPathI.class.getTypeName())); + } + + public interface LibI {} + + public interface ClassPathI extends LibI {} + + public static class Main { + + public static void main(String[] args) throws ClassNotFoundException { + System.out.println( + Class.forName( + "com.android.tools.r8.naming.applymapping" + + ".ApplyMappingClassPathInterfaceInheritTest$ClassPathI") + .getName()); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/naming/b72391662/B72391662.java b/src/test/java/com/android/tools/r8/naming/b72391662/B72391662.java index ddf20ef..c4c9fdf 100644 --- a/src/test/java/com/android/tools/r8/naming/b72391662/B72391662.java +++ b/src/test/java/com/android/tools/r8/naming/b72391662/B72391662.java
@@ -104,7 +104,7 @@ } private static boolean vmVersionIgnored() { - return !ToolHelper.getDexVm().getVersion().isAtLeast(Version.V7_0_0); + return !ToolHelper.getDexVm().getVersion().isNewerThanOrEqual(Version.V7_0_0); } @Test
diff --git a/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java b/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java index ff61668..5c48866 100644 --- a/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java +++ b/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java
@@ -91,13 +91,13 @@ assertNotNull(f2); // TODO(b/72858955): due to the potential reflective access, they should have different names // by R8's improved reflective access detection or via keep rules. - assertEquals(overloadaggressively, f1.field.name == f2.field.name); + assertEquals(overloadaggressively, f1.getReference().name == f2.getReference().name); DexEncodedField f3 = a.field(B.class.getCanonicalName(), "f3").getField(); assertNotNull(f3); // TODO(b/72858955): ditto - assertEquals(overloadaggressively, f1.field.name == f3.field.name); + assertEquals(overloadaggressively, f1.getReference().name == f3.getReference().name); // TODO(b/72858955): ditto - assertEquals(overloadaggressively, f2.field.name == f3.field.name); + assertEquals(overloadaggressively, f2.getReference().name == f3.getReference().name); String main = FieldUpdater.class.getCanonicalName(); ProcessResult javaOutput = runOnJavaRaw(main, classes); @@ -143,7 +143,7 @@ assertNotNull(f3); // TODO(b/72858955): due to the potential reflective access, they should have different names // by R8's improved reflective access detection or via keep rules. - assertEquals(overloadaggressively, f1.field.name == f3.field.name); + assertEquals(overloadaggressively, f1.getReference().name == f3.getReference().name); String main = FieldResolution.class.getCanonicalName(); ProcessResult javaOutput = runOnJavaRaw(main, classes); @@ -188,14 +188,14 @@ DexEncodedMethod m2 = b.method("java.lang.Object", "getF2", ImmutableList.of()).getMethod(); // TODO(b/72858955): due to the potential reflective access, they should have different names. - assertEquals(overloadaggressively, m1.method.name == m2.method.name); + assertEquals(overloadaggressively, m1.getReference().name == m2.getReference().name); DexEncodedMethod m3 = b.method("java.lang.String", "getF3", ImmutableList.of()).getMethod(); assertNotNull(m3); // TODO(b/72858955): ditto - assertEquals(overloadaggressively, m1.method.name == m3.method.name); + assertEquals(overloadaggressively, m1.getReference().name == m3.getReference().name); // TODO(b/72858955): ditto - assertEquals(overloadaggressively, m2.method.name == m3.method.name); + assertEquals(overloadaggressively, m2.getReference().name == m3.getReference().name); String main = MethodResolution.class.getCanonicalName(); ProcessResult javaOutput = runOnJavaRaw(main, classes);
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java b/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java index 668206c..34d84c4 100644 --- a/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java +++ b/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.SingleTestRunResult; import com.android.tools.r8.ToolHelper.DexVm; +import com.android.tools.r8.references.ClassReference; import com.android.tools.r8.retrace.Retrace; import com.android.tools.r8.retrace.RetraceCommand; import com.android.tools.r8.utils.StringUtils; @@ -17,6 +18,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -54,6 +56,10 @@ return addWithoutFileNameAndLineNumber(clazz.getTypeName(), methodName); } + public Builder addWithoutFileNameAndLineNumber(ClassReference clazz, String methodName) { + return addWithoutFileNameAndLineNumber(clazz.getTypeName(), methodName); + } + public Builder addWithoutFileNameAndLineNumber(String className, String methodName) { stackTraceLines.add( StackTraceLine.builder().setClassName(className).setMethodName(methodName).build()); @@ -65,12 +71,19 @@ return this; } + public Builder applyIf(boolean condition, Consumer<Builder> fn) { + if (condition) { + fn.accept(this); + } + return this; + } + public StackTrace build() { return new StackTrace( stackTraceLines, StringUtils.join( - stackTraceLines.stream().map(StackTraceLine::toString).collect(Collectors.toList()), - "\n")); + "\n", + stackTraceLines.stream().map(StackTraceLine::toString).collect(Collectors.toList()))); } }
diff --git a/src/test/java/com/android/tools/r8/regress/Regress181837660.java b/src/test/java/com/android/tools/r8/regress/Regress181837660.java index 7fd9e77..b5e0a7c 100644 --- a/src/test/java/com/android/tools/r8/regress/Regress181837660.java +++ b/src/test/java/com/android/tools/r8/regress/Regress181837660.java
@@ -4,6 +4,8 @@ package com.android.tools.r8.regress; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -14,7 +16,6 @@ import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.ToolHelper.ProcessResult; import com.android.tools.r8.dexsplitter.SplitterTestBase; -import com.android.tools.r8.utils.StringUtils; import com.google.common.collect.ImmutableSet; import org.junit.Test; import org.junit.runner.RunWith; @@ -28,8 +29,6 @@ @RunWith(Parameterized.class) public class Regress181837660 extends SplitterTestBase { - public static final String EXPECTED = StringUtils.lines("42"); - @Parameters(name = "{0}") public static TestParametersCollection params() { return getTestParameters().withDexRuntimes().withAllApiLevels().build(); @@ -67,10 +66,26 @@ FeatureClass.class, b -> {}, this::configureNoInlineAnnotations); - // TODO(b/181571571): This should not succeed as illustrated by non inlining case - assertEquals(0, processResult.exitCode); + // This should not succeed as illustrated by non inlining case + assertEquals(1, processResult.exitCode); // We can't actually read the field since it is in the feature. - assertFalse(processResult.stderr.contains("NoClassDefFoundError")); + assertThat(processResult.stderr, containsString("NoClassDefFoundError")); + } + + @Test + public void testRegress181571571StillInlineValid() throws Exception { + ProcessResult processResult = + testR8Splitter( + parameters, + ImmutableSet.of(Base2Class.class), + ImmutableSet.of(Feature2Class.class), + Feature2Class.class, + r8TestCompileResult -> + r8TestCompileResult.inspect( + base -> assertFalse(base.clazz(Base2Class.class).isPresent())), + this::configureNoInlineAnnotations); + assertEquals(0, processResult.exitCode); + assertEquals(processResult.stdout, "42\n"); } private void configure(R8FullTestBuilder testBuilder) throws NoSuchMethodException { @@ -83,20 +98,52 @@ } public static class BaseClass { + @NeverInline public static String getFromFeature() { return FeatureClass.featureString; } + + @NeverInline + public static String getSecondFromFeature() { + return FeatureClass.getFeatureString(); + } } public static class FeatureClass implements RunInterface { public static String featureString = "22"; + public static String getFeatureString() { + return "42"; + } + public static String getAString() { return BaseClass.getFromFeature(); } + public static String getSecondString() { + return BaseClass.getSecondFromFeature(); + } + + @Override + public void run() { + System.out.println(getAString()); + System.out.println(getSecondString()); + } + } + + public static class Base2Class { + public static String getFromFeature() { + return System.currentTimeMillis() > 2 ? "42" : "-19"; + } + } + + public static class Feature2Class implements RunInterface { + public static String getAString() { + return Base2Class.getFromFeature(); + } + @Override public void run() { System.out.println(getAString());
diff --git a/src/test/java/com/android/tools/r8/regress/b111250398/B111250398.java b/src/test/java/com/android/tools/r8/regress/b111250398/B111250398.java index 0556439..33bef6d 100644 --- a/src/test/java/com/android/tools/r8/regress/b111250398/B111250398.java +++ b/src/test/java/com/android/tools/r8/regress/b111250398/B111250398.java
@@ -232,7 +232,7 @@ return Arrays.stream(method.getMethod().getCode().asDexCode().instructions) .filter(instruction -> instruction instanceof IgetObject) .map(instruction -> (IgetObject) instruction) - .filter(get -> get.getField() == field.getField().field) + .filter(get -> get.getField() == field.getField().getReference()) .count(); } @@ -268,23 +268,33 @@ MethodSubject msvOnB = classB.method("void", "msv", ImmutableList.of()); assertThat(msvOnB, isPresent()); // Field load of volatile fields are never eliminated. - assertEquals(5, countIget(mvOnA.getMethod().getCode().asDexCode(), vOnA.getField().field)); - assertEquals(5, countSget(msvOnA.getMethod().getCode().asDexCode(), svOnA.getField().field)); - assertEquals(5, countIget(mvOnB.getMethod().getCode().asDexCode(), vOnA.getField().field)); - assertEquals(5, countSget(msvOnB.getMethod().getCode().asDexCode(), svOnA.getField().field)); + assertEquals( + 5, countIget(mvOnA.getMethod().getCode().asDexCode(), vOnA.getField().getReference())); + assertEquals( + 5, countSget(msvOnA.getMethod().getCode().asDexCode(), svOnA.getField().getReference())); + assertEquals( + 5, countIget(mvOnB.getMethod().getCode().asDexCode(), vOnA.getField().getReference())); + assertEquals( + 5, countSget(msvOnB.getMethod().getCode().asDexCode(), svOnA.getField().getReference())); // For fields on the same class both separate compilation (D8) and whole program // compilation (R8) will eliminate field loads on non-volatile fields. - assertEquals(1, countIget(mfOnA.getMethod().getCode().asDexCode(), fOnA.getField().field)); - assertEquals(1, countSget(msfOnA.getMethod().getCode().asDexCode(), sfOnA.getField().field)); assertEquals( - 2, countIget(mfWithMonitorOnA.getMethod().getCode().asDexCode(), fOnA.getField().field)); + 1, countIget(mfOnA.getMethod().getCode().asDexCode(), fOnA.getField().getReference())); + assertEquals( + 1, countSget(msfOnA.getMethod().getCode().asDexCode(), sfOnA.getField().getReference())); + assertEquals( + 2, + countIget( + mfWithMonitorOnA.getMethod().getCode().asDexCode(), fOnA.getField().getReference())); // For fields on other class both separate compilation (D8) and whole program // compilation (R8) will differ in the eliminated field loads of non-volatile fields. - assertEquals(mfOnBGets, - countIget(mfOnB.getMethod().getCode().asDexCode(), fOnA.getField().field)); - assertEquals(msfOnBGets, - countSget(msfOnB.getMethod().getCode().asDexCode(), sfOnA.getField().field)); + assertEquals( + mfOnBGets, + countIget(mfOnB.getMethod().getCode().asDexCode(), fOnA.getField().getReference())); + assertEquals( + msfOnBGets, + countSget(msfOnB.getMethod().getCode().asDexCode(), sfOnA.getField().getReference())); } @Test @@ -320,12 +330,17 @@ for (FieldSubject field : new FieldSubject[]{years, months, days}) { - assertEquals(1, - countIget(totalDays.getMethod().getCode().asDexCode(), field.getField().field)); - assertEquals(2, - countIget(totalDaysTimes2.getMethod().getCode().asDexCode(), field.getField().field)); - assertEquals(3, - countIget(totalDaysTimes3.getMethod().getCode().asDexCode(), field.getField().field)); + assertEquals( + 1, + countIget(totalDays.getMethod().getCode().asDexCode(), field.getField().getReference())); + assertEquals( + 2, + countIget( + totalDaysTimes2.getMethod().getCode().asDexCode(), field.getField().getReference())); + assertEquals( + 3, + countIget( + totalDaysTimes3.getMethod().getCode().asDexCode(), field.getField().getReference())); } }
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageTestBase.java b/src/test/java/com/android/tools/r8/repackage/RepackageTestBase.java index 9a1ad72..788bb0a 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageTestBase.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageTestBase.java
@@ -125,7 +125,7 @@ if (isFlattenPackageHierarchy()) { expectedPackageNames.add(packageName != null ? packageName : "a"); } - return StringUtils.join(expectedPackageNames, "."); + return StringUtils.join(".", expectedPackageNames); } }; }
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithDexItemBasedConstStringTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithDexItemBasedConstStringTest.java index e374f2a..624bdfe 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageWithDexItemBasedConstStringTest.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithDexItemBasedConstStringTest.java
@@ -46,7 +46,7 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(TestClass.class) - .addMainDexClassRules(TestClass.class) + .addMainDexKeepClassRules(TestClass.class) .apply(this::configureRepackaging) .setMinApi(parameters.getApiLevel()) .compile()
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithMainDexListTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithMainDexListTest.java index 4fc28f5..81183f5 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageWithMainDexListTest.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithMainDexListTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.repackage; +import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType; import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY; import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; @@ -13,6 +14,7 @@ import com.android.tools.r8.OutputMode; import com.android.tools.r8.R8TestCompileResult; import com.android.tools.r8.TestParameters; +import com.android.tools.r8.errors.UnsupportedMainDexListUsageDiagnostic; import com.android.tools.r8.utils.codeinspector.CodeInspector; import com.google.common.collect.ImmutableList; import java.nio.file.Path; @@ -22,6 +24,7 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; +// TODO(b/181858113): This test is likely obsolete once main-dex-list support is removed. @RunWith(Parameterized.class) public class RepackageWithMainDexListTest extends RepackageTestBase { @@ -54,7 +57,13 @@ // Debug mode to enable minimal main dex. .debug() .setMinApi(parameters.getApiLevel()) - .compile() + .allowDiagnosticMessages() + .compileWithExpectedDiagnostics( + diagnostics -> + diagnostics + .assertOnlyWarnings() + .assertWarningsMatch( + diagnosticType(UnsupportedMainDexListUsageDiagnostic.class))) .apply(this::checkCompileResult) .run(parameters.getRuntime(), TestClass.class) .assertSuccessWithOutputLines("Hello world!");
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java index 75d4bbc..4d4419f 100644 --- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java +++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
@@ -4,17 +4,17 @@ package com.android.tools.r8.resolution; import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar; -import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import com.android.tools.r8.CompilationFailedException; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.ToolHelper.DexVm; +import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.ResolutionResult; -import com.android.tools.r8.graph.ResolutionResult.IllegalAccessOrNoSuchMethodResult; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.google.common.collect.ImmutableList; import java.io.IOException; @@ -30,17 +30,24 @@ public class VirtualOverrideOfPrivateStaticMethodTest extends TestBase { public interface I { - default void f() {} + default void f() { + System.out.println("I::f"); + } } public static class A { - private static void f() {} + private static void f() { + System.out.println("A::f"); + } } public static class B extends A implements I {} public static class C extends B { - public void f() {} + @Override + public void f() { + System.out.println("C::f"); + } } public static class Main { @@ -64,13 +71,13 @@ .appInfo(); } - private static DexMethod buildMethod(Class clazz, String name) { + private static DexMethod buildMethod(Class<?> clazz, String name) { return buildNullaryVoidMethod(clazz, name, appInfo.dexItemFactory()); } @Parameters(name = "{0}") public static TestParametersCollection data() { - return getTestParameters().withAllRuntimes().withAllApiLevels().build(); + return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(); } private final TestParameters parameters; @@ -85,30 +92,48 @@ @Test public void resolveTarget() { ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB, methodOnB.holder); - assertTrue(resolutionResult instanceof IllegalAccessOrNoSuchMethodResult); + DexClass context = appInfo.definitionFor(methodOnB.holder); + assertTrue(resolutionResult.isIllegalAccessErrorResult(context, appInfo)); } @Test - public void runTest() throws ExecutionException, CompilationFailedException, IOException { - if (parameters.isCfRuntime()) { - testForJvm() - .addProgramClasses(CLASSES) - .run(parameters.getRuntime(), Main.class) - .assertFailureWithErrorThatMatches(containsString(expectedRuntimeError())); - } + public void testJvm() throws Exception { + assumeTrue(parameters.isCfRuntime()); + testForJvm() + .addProgramClasses(CLASSES) + .run(parameters.getRuntime(), Main.class) + .assertFailureWithErrorThatThrows(IllegalAccessError.class); + } + + @Test + public void testD8() throws ExecutionException, CompilationFailedException, IOException { + testForD8(parameters.getBackend()) + .addProgramClasses(CLASSES) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + // TODO(b/182335909): Ideally, this should IllegalAccessError. + .applyIf( + parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring() + && parameters.isCfRuntime(), + r -> r.assertFailureWithErrorThatThrows(IllegalAccessError.class), + r -> r.assertSuccessWithOutputLines("C::f")); + } + + @Test + public void testR8() throws ExecutionException, CompilationFailedException, IOException { testForR8(parameters.getBackend()) .addProgramClasses(CLASSES) .addKeepMainRule(Main.class) .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class) - .assertFailureWithErrorThatMatches(containsString(expectedRuntimeError())); + .assertFailureWithErrorThatThrows(expectedRuntimeError()); } - private String expectedRuntimeError() { + private Class<? extends Throwable> expectedRuntimeError() { if (parameters.isDexRuntime() && parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) { - return "IncompatibleClassChangeError"; + return IncompatibleClassChangeError.class; } - return "IllegalAccessError"; + return IllegalAccessError.class; } }
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java index c92f813..edc4c42 100644 --- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java +++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
@@ -132,7 +132,7 @@ ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(methodOnBReference.holder, methodOnBReference); DexEncodedMethod resolved = resolutionResult.getSingleTarget(); - assertEquals(methodOnBReference, resolved.method); + assertEquals(methodOnBReference, resolved.getReference()); assertFalse(resolutionResult.isVirtualTarget()); DexEncodedMethod singleVirtualTarget = appInfo.lookupSingleVirtualTarget(methodOnBReference, methodOnB, false); @@ -144,7 +144,7 @@ ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(methodOnBReference.holder, methodOnBReference); DexEncodedMethod resolved = resolutionResult.getSingleTarget(); - assertEquals(methodOnBReference, resolved.method); + assertEquals(methodOnBReference, resolved.getReference()); assertFalse(resolutionResult.isVirtualTarget()); }
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java index 2ffd43d..7843995 100644 --- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java +++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
@@ -176,7 +176,7 @@ DexProgramClass bClass = appInfo.definitionForProgramType(methodOnB.holder); ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB, methodOnB.holder); DexEncodedMethod resolved = resolutionResult.getSingleTarget(); - assertEquals(methodOnA, resolved.method); + assertEquals(methodOnA, resolved.getReference()); assertFalse(resolutionResult.isVirtualTarget()); DexEncodedMethod singleVirtualTarget = appInfo.lookupSingleVirtualTarget(methodOnB, bClass.getProgramDefaultInitializer(), false); @@ -187,7 +187,7 @@ public void lookupVirtualTargets() { ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB, methodOnB.holder); DexEncodedMethod resolved = resolutionResult.getSingleTarget(); - assertEquals(methodOnA, resolved.method); + assertEquals(methodOnA, resolved.getReference()); assertFalse(resolutionResult.isVirtualTarget()); }
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java index ce6f4d7..5498d06 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
@@ -18,7 +18,6 @@ import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.ResolutionResult; -import com.android.tools.r8.graph.ResolutionResult.IllegalAccessOrNoSuchMethodResult; import com.android.tools.r8.references.Reference; import com.android.tools.r8.transformers.ClassFileTransformer; import com.android.tools.r8.utils.BooleanUtils; @@ -124,7 +123,11 @@ // Resolution fails when there is a mismatch between the symbolic reference and the definition. if (!symbolicReferenceIsDefiningType) { - assertTrue(resolutionResult instanceof IllegalAccessOrNoSuchMethodResult); + if (inSameNest) { + assertTrue(resolutionResult.isNoSuchMethodErrorResult(callerClassDefinition, appInfo)); + } else { + assertTrue(resolutionResult.isIllegalAccessErrorResult(callerClassDefinition, appInfo)); + } return; }
diff --git a/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java b/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java index c636ef9..e116329 100644 --- a/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java +++ b/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
@@ -67,7 +67,7 @@ appInfo.lookupSingleVirtualTarget(fooA, mainMethod, false, t -> false, typeA, latticeB); assertNotNull(singleTarget); DexMethod fooB = buildNullaryVoidMethod(B.class, "foo", appInfo.dexItemFactory()); - assertEquals(fooB, singleTarget.method); + assertEquals(fooB, singleTarget.getReference()); } @Test @@ -94,7 +94,7 @@ appInfo.lookupSingleVirtualTarget(fooA, mainMethod, false, t -> false, typeA, latticeB); assertNotNull(singleTarget); DexMethod fooB = buildNullaryVoidMethod(B.class, "foo", appInfo.dexItemFactory()); - assertEquals(fooB, singleTarget.method); + assertEquals(fooB, singleTarget.getReference()); } @Test @@ -133,7 +133,7 @@ lookupResult .asLookupResultSuccess() .forEach( - clazzAndMethod -> actual.add(clazzAndMethod.getDefinition().method), + clazzAndMethod -> actual.add(clazzAndMethod.getDefinition().getReference()), lambdaTarget -> { assert false; });
diff --git a/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java b/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java index a4b183c..85bd2ca 100644 --- a/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java +++ b/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java
@@ -55,7 +55,7 @@ DexEncodedMethod singleTarget = appInfo.lookupSingleVirtualTarget(fooA, mainMethod, false, t -> false, typeA, null); assertNotNull(singleTarget); - assertEquals(fooA, singleTarget.method); + assertEquals(fooA, singleTarget.getReference()); DexEncodedMethod invalidSingleTarget = appInfo.lookupSingleVirtualTarget(fooA, mainMethod, true, t -> false, typeA, null); assertNull(invalidSingleTarget); @@ -82,7 +82,7 @@ DexEncodedMethod singleTarget = appInfo.lookupSingleVirtualTarget(fooI, mainMethod, true, t -> false, typeA, null); assertNotNull(singleTarget); - assertEquals(fooA, singleTarget.method); + assertEquals(fooA, singleTarget.getReference()); DexEncodedMethod invalidSingleTarget = appInfo.lookupSingleVirtualTarget(fooI, mainMethod, false, t -> false, typeA, null); assertNull(invalidSingleTarget);
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java new file mode 100644 index 0000000..aa543c8 --- /dev/null +++ b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
@@ -0,0 +1,161 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.retrace; + +import static com.android.tools.r8.naming.retrace.StackTrace.isSameExceptForFileNameAndLineNumber; +import static org.hamcrest.CoreMatchers.containsString; +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.naming.retrace.StackTrace; +import com.android.tools.r8.synthesis.SyntheticItemsTestUtils; +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 RetraceLambdaTest extends TestBase { + + private static final String JAVAC_LAMBDA_METHOD = "lambda$main$0"; + + // TODO(b/172014416): These should not be needed once fixed. + private static final String LAMBDA_BRIDGE_METHOD = "$r8$lambda$dX5OYTAgq4ijGUv_zaGoVsFINMs"; + private static final String INTERNAL_LAMBDA_CLASS = + Main.class.getTypeName() + + "$$InternalSyntheticLambda$0$11a5d582ed94e937718cf3ed497d4d164b60dfa85d606466457007fade57dce8$0"; + + @Parameters(name = "{0}") + public static TestParametersCollection parameters() { + return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(); + } + + private final TestParameters parameters; + + public RetraceLambdaTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testReference() throws Exception { + testForRuntime(parameters) + .addInnerClasses(getClass()) + .run(parameters.getRuntime(), Main.class) + .assertFailureWithErrorThatMatches(containsString("Hello World!")) + .inspectStackTrace( + stackTrace -> { + assertThat( + stackTrace, + isSameExceptForFileNameAndLineNumber( + StackTrace.builder() + .addWithoutFileNameAndLineNumber(Main.class, JAVAC_LAMBDA_METHOD) + // TODO(b/172014416): Support a D8 mapping and prune the synthetic. + .applyIf( + parameters.isDexRuntime(), + b -> + b.addWithoutFileNameAndLineNumber( + SyntheticItemsTestUtils.syntheticLambdaClass(Main.class, 0), + "run")) + .addWithoutFileNameAndLineNumber(Main.class, "runIt") + .addWithoutFileNameAndLineNumber(Main.class, "main") + .build())); + }); + } + + @Test + public void testEverythingInlined() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepMainRule(Main.class) + .addKeepAttributeSourceFile() + .addKeepAttributeLineNumberTable() + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .assertFailureWithErrorThatMatches(containsString("Hello World!")) + .inspectStackTrace( + stackTrace -> { + int frames = parameters.isCfRuntime() ? 2 : 1; + checkRawStackTraceFrameCount(stackTrace, frames, "Expected everything to be inlined"); + checkCurrentlyIncorrectStackTrace(stackTrace, JAVAC_LAMBDA_METHOD); + }); + } + + @Test + public void testNothingInlined() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepMainRule(Main.class) + .addKeepPackageNamesRule(getClass().getPackage()) + .noTreeShaking() + .addKeepAttributeSourceFile() + .addKeepAttributeLineNumberTable() + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .assertFailureWithErrorThatMatches(containsString("Hello World!")) + .inspectStackTrace( + stackTrace -> { + int frames = parameters.isCfRuntime() ? 3 : 5; + checkRawStackTraceFrameCount(stackTrace, frames, "Expected nothing to be inlined"); + checkCurrentlyIncorrectStackTrace(stackTrace, "lambda$main$0"); + }); + } + + private void checkRawStackTraceFrameCount( + StackTrace stackTrace, int expectedFrames, String message) { + int linesFromTest = 0; + for (String line : stackTrace.getOriginalStderr().split("\n")) { + if (line.trim().startsWith("at " + getClass().getPackage().getName())) { + linesFromTest++; + } + } + assertEquals(message + stackTrace.getOriginalStderr(), expectedFrames, linesFromTest); + } + + private void checkCurrentlyIncorrectStackTrace(StackTrace stackTrace, String javacLambdaMethod) { + assertThat( + stackTrace, + isSameExceptForFileNameAndLineNumber( + StackTrace.builder() + .addWithoutFileNameAndLineNumber(Main.class, javacLambdaMethod) + .applyIf( + parameters.isDexRuntime(), + b -> + b + // TODO(b/172014416): Lambda bridges should be marked synthetic + // and removed. + .addWithoutFileNameAndLineNumber(Main.class, LAMBDA_BRIDGE_METHOD) + // TODO(b/172014416): The frame mapping should have removed this + // entry. + // TODO(b/172014416): Synthetics should not map back to internal + // names. + .addWithoutFileNameAndLineNumber(INTERNAL_LAMBDA_CLASS, "run")) + .addWithoutFileNameAndLineNumber(Main.class, "runIt") + .addWithoutFileNameAndLineNumber(Main.class, "main") + .build())); + } + + public interface MyRunner { + void run(); + } + + public static class Main { + + public static void runIt(MyRunner runner) { + runner.run(); + } + + public static void main(String[] args) { + if (args.length == 0) { + runIt( + () -> { + throw new RuntimeException("Hello World!"); + }); + } + } + } +}
diff --git a/src/test/java/com/android/tools/r8/shaking/AbstractSuperClassLiveMethodTest.java b/src/test/java/com/android/tools/r8/shaking/AbstractSuperClassLiveMethodTest.java new file mode 100644 index 0000000..8cdd48e --- /dev/null +++ b/src/test/java/com/android/tools/r8/shaking/AbstractSuperClassLiveMethodTest.java
@@ -0,0 +1,103 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.shaking; + +import com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.NoVerticalClassMerging; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.google.common.collect.ImmutableList; +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 AbstractSuperClassLiveMethodTest extends TestBase { + + private final TestParameters parameters; + private final String NEW_DESCRIPTOR = "Lfoo/A;"; + private final String[] EXPECTED = new String[] {"A::foo", "Base::foo"}; + private final String[] EXPECTED_DALVIK = new String[] {"A::foo", "A::foo"}; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public AbstractSuperClassLiveMethodTest(TestParameters parameters) { + this.parameters = parameters; + } + + public List<byte[]> getProgramClassFileData() throws Exception { + return ImmutableList.of( + transformer(A.class).setClassDescriptor(NEW_DESCRIPTOR).transform(), + transformer(Main.class) + .replaceClassDescriptorInMethodInstructions(descriptor(A.class), NEW_DESCRIPTOR) + .transform()); + } + + @Test + public void testRuntime() throws Exception { + testForRuntime(parameters) + .addProgramClasses(Base.class) + .addProgramClassFileData(getProgramClassFileData()) + .run(parameters.getRuntime(), Main.class) + .applyIf( + parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isDalvik(), + r -> r.assertSuccessWithOutputLines(EXPECTED_DALVIK), + r -> r.assertSuccessWithOutputLines(EXPECTED)); + } + + @Test + public void testForR8() throws Exception { + testForR8(parameters.getBackend()) + .addProgramClasses(Base.class) + .addProgramClassFileData(getProgramClassFileData()) + .setMinApi(parameters.getApiLevel()) + .addKeepMainRule(Main.class) + .enableInliningAnnotations() + .enableNoVerticalClassMergingAnnotations() + .enableNeverClassInliningAnnotations() + .addOptionsModification(options -> options.enableDevirtualization = false) + .run(parameters.getRuntime(), Main.class) + .applyIf( + parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isDalvik(), + r -> r.assertSuccessWithOutputLines(EXPECTED_DALVIK), + // TODO(b/182444403): Should succeed with EXPECTED. + r -> r.assertFailureWithErrorThatThrows(AbstractMethodError.class)); + } + + @NoVerticalClassMerging + public abstract static class Base { + + @NeverInline + void foo() { + System.out.println("Base::foo"); + } + } + + @NeverClassInline + public static class /* will be foo.A */ A extends Base { + + @Override + @NeverInline + public void foo() { + System.out.println("A::foo"); + } + } + + public static class Main { + + public static void main(String[] args) { + Base a = new A(); + ((A) a).foo(); + a.foo(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/shaking/AsterisksTest.java b/src/test/java/com/android/tools/r8/shaking/AsterisksTest.java index ddaf47f..aa2df28 100644 --- a/src/test/java/com/android/tools/r8/shaking/AsterisksTest.java +++ b/src/test/java/com/android/tools/r8/shaking/AsterisksTest.java
@@ -99,9 +99,9 @@ DexClass clazz = classSubject.getDexProgramClass(); assertEquals(3, clazz.getMethodCollection().numberOfVirtualMethods()); for (DexEncodedMethod encodedMethod : clazz.virtualMethods()) { - assertTrue(encodedMethod.method.name.toString().startsWith("foo")); + assertTrue(encodedMethod.getReference().name.toString().startsWith("foo")); MethodSubject methodSubject = - classSubject.method(MethodSignature.fromDexMethod(encodedMethod.method)); + classSubject.method(MethodSignature.fromDexMethod(encodedMethod.getReference())); assertThat(methodSubject, isPresentAndNotRenamed()); } } @@ -135,9 +135,9 @@ DexClass clazz = classSubject.getDexProgramClass(); assertEquals(3, clazz.getMethodCollection().numberOfVirtualMethods()); for (DexEncodedMethod encodedMethod : clazz.virtualMethods()) { - assertTrue(encodedMethod.method.name.toString().startsWith("foo")); + assertTrue(encodedMethod.getReference().name.toString().startsWith("foo")); MethodSubject methodSubject = - classSubject.method(MethodSignature.fromDexMethod(encodedMethod.method)); + classSubject.method(MethodSignature.fromDexMethod(encodedMethod.getReference())); assertThat(methodSubject, isPresentAndNotRenamed()); } } @@ -155,9 +155,9 @@ DexClass clazz = classSubject.getDexProgramClass(); assertEquals(3, clazz.getMethodCollection().numberOfVirtualMethods()); for (DexEncodedMethod encodedMethod : clazz.virtualMethods()) { - assertTrue(encodedMethod.method.name.toString().startsWith("foo")); + assertTrue(encodedMethod.getReference().name.toString().startsWith("foo")); MethodSubject methodSubject = - classSubject.method(MethodSignature.fromDexMethod(encodedMethod.method)); + classSubject.method(MethodSignature.fromDexMethod(encodedMethod.getReference())); assertThat(methodSubject, isPresentAndNotRenamed()); } }
diff --git a/src/test/java/com/android/tools/r8/shaking/FieldReadsJasminTest.java b/src/test/java/com/android/tools/r8/shaking/FieldReadsJasminTest.java index 3f27bc6..c3e53cf 100644 --- a/src/test/java/com/android/tools/r8/shaking/FieldReadsJasminTest.java +++ b/src/test/java/com/android/tools/r8/shaking/FieldReadsJasminTest.java
@@ -254,7 +254,9 @@ .filter(InstructionSubject::isStaticGet) .anyMatch( instruction -> - instruction.getField().equals(clinitFieldSubject.getField().field))); + instruction + .getField() + .equals(clinitFieldSubject.getField().getReference()))); }); }
diff --git a/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInInterfaceMarkingTest.java b/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInInterfaceMarkingTest.java index 437cdd2..42268b2 100644 --- a/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInInterfaceMarkingTest.java +++ b/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInInterfaceMarkingTest.java
@@ -58,7 +58,7 @@ AppInfoWithLiveness appInfo, DexType type) { DexProgramClass clazz = appInfo.definitionFor(type).asProgramClass(); DexEncodedMethod method = - clazz.lookupVirtualMethod(m -> m.method.name.toString().equals("isEmpty")); + clazz.lookupVirtualMethod(m -> m.getReference().name.toString().equals("isEmpty")); assertTrue(method.isLibraryMethodOverride().isTrue()); }
diff --git a/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInLambdaMarkingTest.java b/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInLambdaMarkingTest.java index 331eb12..563a312 100644 --- a/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInLambdaMarkingTest.java +++ b/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInLambdaMarkingTest.java
@@ -61,7 +61,7 @@ AppInfoWithLiveness appInfo, DexType type) { DexProgramClass clazz = appInfo.definitionFor(type).asProgramClass(); DexEncodedMethod method = - clazz.lookupVirtualMethod(m -> m.method.name.toString().equals("iterator")); + clazz.lookupVirtualMethod(m -> m.getReference().name.toString().equals("iterator")); // TODO(b/149976493): Mark library overrides from lambda instances. if (parameters.isCfRuntime()) { assertTrue(method.isLibraryMethodOverride().isFalse());
diff --git a/src/test/java/com/android/tools/r8/shaking/NonVirtualOverrideTest.java b/src/test/java/com/android/tools/r8/shaking/NonVirtualOverrideTest.java index f98e5ea..4a8306a 100644 --- a/src/test/java/com/android/tools/r8/shaking/NonVirtualOverrideTest.java +++ b/src/test/java/com/android/tools/r8/shaking/NonVirtualOverrideTest.java
@@ -144,7 +144,7 @@ return false; } Version version = parameters.getRuntime().asDex().getVm().getVersion(); - return version.isOlderThanOrEqual(Version.V7_0_0) && version.isAtLeast(Version.V5_1_1); + return version.isOlderThanOrEqual(Version.V7_0_0) && version.isNewerThanOrEqual(Version.V5_1_1); } public static R8TestCompileResult compile(Dimensions dimensions) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/shaking/attributes/InnerClassesSimpleTest.java b/src/test/java/com/android/tools/r8/shaking/attributes/InnerClassesSimpleTest.java new file mode 100644 index 0000000..0474186 --- /dev/null +++ b/src/test/java/com/android/tools/r8/shaking/attributes/InnerClassesSimpleTest.java
@@ -0,0 +1,76 @@ +// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.shaking.attributes; + +import static org.hamcrest.CoreMatchers.containsString; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestShrinkerBuilder; +import com.android.tools.r8.utils.BooleanUtils; +import java.nio.file.Path; +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 InnerClassesSimpleTest extends TestBase { + + private final TestParameters parameters; + private final boolean minify; + + @Parameters(name = "{0}, minify: {1}") + public static List<Object[]> data() { + return buildParameters(getTestParameters().withCfRuntimes().build(), BooleanUtils.values()); + } + + public InnerClassesSimpleTest(TestParameters parameters, boolean minify) { + this.parameters = parameters; + this.minify = minify; + } + + @Test + public void testR8() throws Exception { + Path path = + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepMainRule(Main.class) + .addKeepPackageNamesRule(getClass().getPackage()) + .noTreeShaking() + .applyIf(!minify, TestShrinkerBuilder::noMinification) + .compile() + .writeToZip(); + testForR8(parameters.getBackend()) + .addProgramFiles(path) + .addKeepAllClassesRule() + .allowDiagnosticInfoMessages(minify) + .compile() + // TODO(b/182524171): Prune inner class attributes if they are not kept. + .assertAllInfoMessagesMatch(containsString("Malformed inner-class attribute")) + .assertInfosCount(minify ? 4 : 0) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("Hello World"); + } + + public interface MyRunner { + void run(); + } + + public static class Main { + + public static void runIt(MyRunner runner) { + runner.run(); + } + + public static void main(String[] args) { + runIt( + () -> { + System.out.println("Hello World"); + }); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking15Test.java b/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking15Test.java index 7111f51..34da969 100644 --- a/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking15Test.java +++ b/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking15Test.java
@@ -74,13 +74,13 @@ } private static void checkFieldInDictionary(FieldSubject field) { - if (!names.contains(field.getField().field.name.toSourceString())) { + if (!names.contains(field.getField().getReference().name.toSourceString())) { throw new AssertionError(); } } private static void checkMethodInDictionary(MethodSubject method) { - String name = method.getMethod().method.name.toSourceString(); + String name = method.getMethod().getReference().name.toSourceString(); if (!names.contains(name) && !name.equals("<init>") && !name.equals("main")) { throw new AssertionError(); }
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/applymapping/IfRuleWithApplyMappingTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/applymapping/IfRuleWithApplyMappingTest.java index 311d6a6..e841ffc 100644 --- a/src/test/java/com/android/tools/r8/shaking/ifrule/applymapping/IfRuleWithApplyMappingTest.java +++ b/src/test/java/com/android/tools/r8/shaking/ifrule/applymapping/IfRuleWithApplyMappingTest.java
@@ -65,7 +65,8 @@ inspector.clazz(IfRuleWithApplyMappingTestClass.class).uniqueMethodWithName("method"); assertThat(methodSubject, isPresent()); assertEquals( - A.class.getTypeName(), methodSubject.getMethod().method.proto.parameters.toSourceString()); + A.class.getTypeName(), + methodSubject.getMethod().getReference().proto.parameters.toSourceString()); } }
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptViaClassInitializerTestRunner.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptViaClassInitializerTestRunner.java index 230c0cf..221f99c 100644 --- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptViaClassInitializerTestRunner.java +++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptViaClassInitializerTestRunner.java
@@ -100,7 +100,7 @@ @Test public void testKeptMethod() throws Exception { - assumeTrue(ToolHelper.getDexVm().getVersion().isAtLeast(Version.V7_0_0)); + assumeTrue(ToolHelper.getDexVm().getVersion().isNewerThanOrEqual(Version.V7_0_0)); MethodReference mainMethod = methodFromMethod(Main.class.getDeclaredMethod("main", String[].class));
diff --git a/src/test/java/com/android/tools/r8/smali/ConstantFoldingTest.java b/src/test/java/com/android/tools/r8/smali/ConstantFoldingTest.java index e5a8027..b9a9dc8 100644 --- a/src/test/java/com/android/tools/r8/smali/ConstantFoldingTest.java +++ b/src/test/java/com/android/tools/r8/smali/ConstantFoldingTest.java
@@ -55,10 +55,12 @@ assertEquals(1, getNumberOfProgramClasses(processdApplication)); CodeInspector inspector = new CodeInspector(processdApplication); ClassSubject clazz = inspector.clazz(DEFAULT_CLASS_NAME); - clazz.forAllMethods(method -> { - int index = Integer.parseInt(method.getMethod().method.name.toString().substring(1)); - checkers.get(index).accept(method.getMethod(), values.get(index)); - }); + clazz.forAllMethods( + method -> { + int index = + Integer.parseInt(method.getMethod().getReference().name.toString().substring(1)); + checkers.get(index).accept(method.getMethod(), values.get(index)); + }); } }
diff --git a/src/test/java/com/android/tools/r8/smali/OutlineTest.java b/src/test/java/com/android/tools/r8/smali/OutlineTest.java index a7b67bf..9324b87 100644 --- a/src/test/java/com/android/tools/r8/smali/OutlineTest.java +++ b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
@@ -870,7 +870,7 @@ List<DexType> r = new ArrayList<>(); for (DexEncodedMethod directMethod : outlineMethods) { if (directMethod.getCode().asDexCode().instructions[0] instanceof InvokeVirtual) { - r.add(directMethod.method.proto.returnType); + r.add(directMethod.getReference().proto.returnType); } } assertEquals(2, r.size());
diff --git a/src/test/java/com/android/tools/r8/smali/SmaliBuilder.java b/src/test/java/com/android/tools/r8/smali/SmaliBuilder.java index e9368e9..0a2c7ab 100644 --- a/src/test/java/com/android/tools/r8/smali/SmaliBuilder.java +++ b/src/test/java/com/android/tools/r8/smali/SmaliBuilder.java
@@ -42,8 +42,14 @@ @Override public String toString() { - return returnType + " " + clazz + "." + name - + "(" + StringUtils.join(parameterTypes, ",") + ")"; + return returnType + + " " + + clazz + + "." + + name + + "(" + + StringUtils.join(",", parameterTypes) + + ")"; } }
diff --git a/src/test/java/com/android/tools/r8/testing/StackTraceTest.java b/src/test/java/com/android/tools/r8/testing/StackTraceTest.java index 33915ef..41b6de3 100644 --- a/src/test/java/com/android/tools/r8/testing/StackTraceTest.java +++ b/src/test/java/com/android/tools/r8/testing/StackTraceTest.java
@@ -40,12 +40,12 @@ public void testJvmStackTrace() throws Exception { String stderr = StringUtils.join( + "\n", ImmutableList.of( "Exception in thread \"main\" java.lang.RuntimeException", "\tat com.example.A.method2(Test.java:30)", "\tat com.example.A.method1(Test.java:20)", - "\tat com.example.Main.main(Test.java:10)"), - "\n"); + "\tat com.example.Main.main(Test.java:10)")); checkStackTrace(StackTrace.extractFromJvm(stderr)); } @@ -95,8 +95,7 @@ "\tat com.example.Main.main(Test.java:10)", "dex2oat I 10-30 11:41:40 232588 232588 dex2oat.cc:2808] dex2oat took 94.860ms" + " (71.941ms cpu) (threads: 72) arena alloc=3KB (3312B) java alloc=32KB (32800B)" - + " native alloc=440KB (450720B) free=9MB (9539424B)" - ); + + " native alloc=440KB (450720B) free=9MB (9539424B)"); checkStackTrace(StackTrace.extractFromArt(stderr, DexVm.ART_5_1_1_HOST)); }
diff --git a/src/test/java/com/android/tools/r8/utils/AppComparator.java b/src/test/java/com/android/tools/r8/utils/AppComparator.java index 3436b9a..9dcec97 100644 --- a/src/test/java/com/android/tools/r8/utils/AppComparator.java +++ b/src/test/java/com/android/tools/r8/utils/AppComparator.java
@@ -60,10 +60,11 @@ CodeInspector inspect2 = new CodeInspector(app2, Paths.get(MAP_2)); // Define your own tester to pick methods to inspect. - Predicate<DexEncodedMethod> methodTester = encodedMethod -> { - return encodedMethod.method.name.toString().equals("run") - && encodedMethod.method.getArity() == 0; - }; + Predicate<DexEncodedMethod> methodTester = + encodedMethod -> { + return encodedMethod.getReference().name.toString().equals("run") + && encodedMethod.getReference().getArity() == 0; + }; inspect1.forAllClasses(clazz1 -> { clazz1.forAllMethods(method1 -> {
diff --git a/src/test/java/com/android/tools/r8/utils/Smali.java b/src/test/java/com/android/tools/r8/utils/Smali.java index 693af00..26e85e5 100644 --- a/src/test/java/com/android/tools/r8/utils/Smali.java +++ b/src/test/java/com/android/tools/r8/utils/Smali.java
@@ -79,7 +79,7 @@ if (parser.getNumberOfSyntaxErrors() > 0 || lexer.getNumberOfSyntaxErrors() > 0) { throw new RuntimeException( - "Error occured while compiling text:\n" + StringUtils.join(smaliTexts, "\n")); + "Error occured while compiling text:\n" + StringUtils.join("\n", smaliTexts)); } CommonTree t = result.getTree();
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java index 7059ae1..2b57e91 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java
@@ -19,7 +19,7 @@ if (!targetSubject.isPresent()) { throw new IllegalArgumentException(); } - DexField target = targetSubject.getField().field; + DexField target = targetSubject.getField().getReference(); return new TypeSafeMatcher<MethodSubject>() { @Override protected boolean matchesSafely(MethodSubject subject) { @@ -79,7 +79,7 @@ if (!targetSubject.isPresent()) { throw new IllegalArgumentException(); } - DexMethod target = targetSubject.getMethod().method; + DexMethod target = targetSubject.getMethod().getReference(); return new TypeSafeMatcher<MethodSubject>() { @Override protected boolean matchesSafely(MethodSubject subject) {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FieldSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FieldSubject.java index ef44c64..aae1912 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/FieldSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FieldSubject.java
@@ -15,7 +15,7 @@ public abstract DexEncodedField getField(); public DexField getDexField() { - return getField().field; + return getField().getReference(); } public abstract DexValue getStaticValue();
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java index ed04f35..be358de 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -121,7 +121,7 @@ private DexEncodedMethod findMethod(Iterable<DexEncodedMethod> methods, DexMethod dexMethod) { for (DexEncodedMethod method : methods) { - if (method.method.equals(dexMethod)) { + if (method.getReference().equals(dexMethod)) { return method; } } @@ -320,7 +320,7 @@ private DexEncodedField findField(List<DexEncodedField> fields, DexField dexField) { for (DexEncodedField field : fields) { - if (field.field.equals(dexField)) { + if (field.getReference().equals(dexField)) { return field; } }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java index b071916..023f412 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
@@ -43,7 +43,7 @@ } public TypeSubject type() { - return new TypeSubject(codeInspector, dexField.field.type); + return new TypeSubject(codeInspector, dexField.getReference().type); } @Override @@ -79,7 +79,7 @@ @Override public FieldSignature getFinalSignature() { - return FieldSignature.fromDexField(dexField.field); + return FieldSignature.fromDexField(dexField.getReference()); } @Override @@ -123,7 +123,9 @@ @Override public String getJvmFieldSignatureAsString() { - return dexField.field.name.toString() + ":" + dexField.field.type.toDescriptorString(); + return dexField.getReference().name.toString() + + ":" + + dexField.getReference().type.toDescriptorString(); } @Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java index dfccf5a..0eb0de1 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -155,7 +155,7 @@ @Override public MethodSignature getFinalSignature() { - return MethodSignature.fromDexMethod(dexMethod.method); + return MethodSignature.fromDexMethod(dexMethod.getReference()); } @Override @@ -273,7 +273,7 @@ } Object2IntMap<InstructionSubject> lineNumberTable = new Object2IntOpenHashMap<>(); DexDebugPositionState state = - new DexDebugPositionState(debugInfo.startLine, getMethod().method); + new DexDebugPositionState(debugInfo.startLine, getMethod().getReference()); Iterator<DexDebugEvent> iterator = Arrays.asList(debugInfo.events).iterator(); for (Instruction insn : code.instructions) { int offset = insn.getOffset(); @@ -337,7 +337,7 @@ } public MethodReference asMethodReference() { - DexMethod method = dexMethod.method; + DexMethod method = dexMethod.getReference(); return Reference.method( Reference.classFromDescriptor(method.holder.toDescriptorString()), method.name.toString(), @@ -349,13 +349,15 @@ @Override public String getJvmMethodSignatureAsString() { - return dexMethod.method.name.toString() + return dexMethod.getName().toString() + "(" + StringUtils.join( - Arrays.stream(dexMethod.method.proto.parameters.values) - .map(DexType::toDescriptorString).collect(Collectors.toList()), "") + "", + Arrays.stream(dexMethod.getParameters().values) + .map(DexType::toDescriptorString) + .collect(Collectors.toList())) + ")" - + dexMethod.method.proto.returnType.toDescriptorString(); + + dexMethod.returnType().toDescriptorString(); } @Override
diff --git a/tools/archive_desugar_jdk_libs.py b/tools/archive_desugar_jdk_libs.py index 403212f..825cb91 100755 --- a/tools/archive_desugar_jdk_libs.py +++ b/tools/archive_desugar_jdk_libs.py
@@ -85,10 +85,12 @@ 'https://github.com/' + github_account + '/' + LIBRARY_NAME, checkout_dir) -def BuildDesugaredLibrary(checkout_dir): +def BuildDesugaredLibrary(checkout_dir, variant): + if (variant != 'jdk8' and variant != 'jdk11'): + raise Exception('Variant ' + variant + 'is not supported') with utils.ChangedWorkingDirectory(checkout_dir): bazel = os.path.join(utils.BAZEL_TOOL, 'lib', 'bazel', 'bin', 'bazel') - cmd = [bazel, 'build', 'maven_release'] + cmd = [bazel, 'build', 'maven_release' + ('_jdk11' if variant == 'jdk11' else '')] utils.PrintCmd(cmd) subprocess.check_call(cmd) cmd = [bazel, 'shutdown'] @@ -97,9 +99,16 @@ # Locate the library jar and the maven zip with the jar from the # bazel build. - library_jar = os.path.join( - checkout_dir, 'bazel-bin', 'src', 'share', 'classes', 'java', 'libjava.jar') - maven_zip = os.path.join(checkout_dir, 'bazel-bin', LIBRARY_NAME +'.zip') + if variant == 'jdk8': + library_jar = os.path.join( + checkout_dir, 'bazel-bin', 'src', 'share', 'classes', 'java', 'libjava.jar') + else: + library_jar = os.path.join( + checkout_dir, 'bazel-bin', 'jdk11', 'src', 'java_base_selected.jar') + maven_zip = os.path.join( + checkout_dir, + 'bazel-bin', + LIBRARY_NAME + ('_jdk11' if variant != 'jdk11' else '') +'.zip') return (library_jar, maven_zip) @@ -124,11 +133,12 @@ # Make sure bazel is extracted in third_party. utils.DownloadFromGoogleCloudStorage(utils.BAZEL_SHA_FILE) utils.DownloadFromGoogleCloudStorage(utils.JAVA8_SHA_FILE) + utils.DownloadFromGoogleCloudStorage(utils.JAVA11_SHA_FILE) if options.build_only: with utils.TempDir() as checkout_dir: CloneDesugaredLibrary(options.github_account, checkout_dir) - (library_jar, maven_zip) = BuildDesugaredLibrary(checkout_dir) + (library_jar, maven_zip) = BuildDesugaredLibrary(checkout_dir, "jdk8") shutil.copyfile( library_jar, os.path.join(options.build_only, os.path.basename(library_jar))) @@ -150,7 +160,7 @@ raise Exception( 'Target archive directory %s already exists' % destination) - (library_jar, maven_zip) = BuildDesugaredLibrary(checkout_dir) + (library_jar, maven_zip) = BuildDesugaredLibrary(checkout_dir, "jdk8") storage_path = LIBRARY_NAME + '/' + version # Upload the jar file with the library.
diff --git a/tools/test.py b/tools/test.py index 9e2a3e2..f7b204f 100755 --- a/tools/test.py +++ b/tools/test.py
@@ -162,6 +162,8 @@ help='Enable Java debug agent and suspend compilation (default disabled)', default=False, action='store_true') + result.add_option('--desugared-library-configuration', '--desugared_library-configuration', + help='Use alternative desugared library configuration.') result.add_option('--desugared-library', '--desugared_library', help='Build and use desugared library from GitHub.') return result.parse_args() @@ -181,6 +183,13 @@ if utils.is_bot(): gradle.RunGradle(['--no-daemon', 'clean']) + desugar_jdk_json_dir = None + if options.desugared_library_configuration: + if options.desugared_library_configuration != 'jdk11': + print("Only value supported for --desugared-library is 'jdk11'") + exit(1) + desugar_jdk_json_dir = 'src/library_desugar/jdk11' + desugar_jdk_libs = None if options.desugared_library: if options.desugared_library != 'HEAD': @@ -195,12 +204,12 @@ # Make sure bazel is extracted in third_party. utils.DownloadFromGoogleCloudStorage(utils.BAZEL_SHA_FILE) utils.DownloadFromGoogleCloudStorage(utils.JAVA8_SHA_FILE) - (library_jar, maven_zip) = archive_desugar_jdk_libs.BuildDesugaredLibrary(checkout_dir) + utils.DownloadFromGoogleCloudStorage(utils.JAVA11_SHA_FILE) + (library_jar, maven_zip) = archive_desugar_jdk_libs.BuildDesugaredLibrary(checkout_dir, 'jdk11' if options.desugared_library_configuration == 'jdk11' else 'jdk8') desugar_jdk_libs = os.path.join(desugar_jdk_libs_dir, os.path.basename(library_jar)) shutil.copyfile(library_jar, desugar_jdk_libs) print('Desugared library for test in ' + desugar_jdk_libs) - gradle_args = ['--stacktrace'] if utils.is_bot(): # Bots don't like dangling processes. @@ -284,6 +293,8 @@ gradle_args.append('--no-daemon') if options.debug_agent: gradle_args.append('--no-daemon') + if desugar_jdk_json_dir: + gradle_args.append('-Pdesugar_jdk_json_dir=' + desugar_jdk_json_dir) if desugar_jdk_libs: gradle_args.append('-Pdesugar_jdk_libs=' + desugar_jdk_libs)
diff --git a/tools/utils.py b/tools/utils.py index 1820991..da4a0e4 100644 --- a/tools/utils.py +++ b/tools/utils.py
@@ -83,6 +83,7 @@ BAZEL_SHA_FILE = os.path.join(THIRD_PARTY, 'bazel.tar.gz.sha1') BAZEL_TOOL = os.path.join(THIRD_PARTY, 'bazel') JAVA8_SHA_FILE = os.path.join(THIRD_PARTY, 'openjdk', 'jdk8', 'linux-x86.tar.gz.sha1') +JAVA11_SHA_FILE = os.path.join(THIRD_PARTY, 'openjdk', 'jdk-11', 'linux.tar.gz.sha1') IGNORE_WARNINGS_RULES = os.path.join(REPO_ROOT, 'src', 'test', 'ignorewarnings.rules') ANDROID_HOME_ENVIROMENT_NAME = "ANDROID_HOME"