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