Merge commit '4c45ccb630775825fc4bff2009944dd8994752ba' into dev-release
diff --git a/build.gradle b/build.gradle
index 01d41fc..17206b1 100644
--- a/build.gradle
+++ b/build.gradle
@@ -46,7 +46,7 @@
     // The kotlin version is only here to specify the kotlin language level,
     // all kotlin compilations are done in tests.
     kotlinVersion = '1.5.0'
-    kotlinExtMetadataJVMVersion = '0.2.0'
+    kotlinExtMetadataJVMVersion = '0.3.0'
     smaliVersion = '2.2b4'
     errorproneVersion = '2.3.2'
     testngVersion = '6.10'
@@ -273,7 +273,8 @@
     apiUsageSampleCompile "com.google.guava:guava:$guavaVersion"
     kotlinR8TestResourcesCompileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
     errorprone("com.google.errorprone:error_prone_core:$errorproneVersion")
-    testImplementation "org.jetbrains.kotlin:kotlin-reflect:1.3.31"
+    testImplementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
+    testImplementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
 }
 
 def r8LibPath = "$buildDir/libs/r8lib.jar"
diff --git a/infra/config/global/generated/cr-buildbucket.cfg b/infra/config/global/generated/cr-buildbucket.cfg
index b8a3edb..8caf056 100644
--- a/infra/config/global/generated/cr-buildbucket.cfg
+++ b/infra/config/global/generated/cr-buildbucket.cfg
@@ -11,7 +11,7 @@
   }
   acls {
     role: SCHEDULER
-    group: "luci-scheduler@appspot.gserviceaccount.com"
+    identity: "user:luci-scheduler@appspot.gserviceaccount.com"
   }
   acls {
     role: SCHEDULER
@@ -21,6 +21,7 @@
     builders {
       name: "archive"
       swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "os:Ubuntu-16.04"
@@ -29,28 +30,18 @@
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "archive:true"
+        properties_j: "archive:\"true\""
+        properties_j: "builder_group:\"internal.client.r8\""
       }
+      priority: 25
       execution_timeout_secs: 1800
+      expiration_secs: 126000
+      build_numbers: YES
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
       name: "archive_release"
       swarming_host: "chrome-swarming.appspot.com"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
-        cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
-        cipd_version: "refs/heads/master"
-        properties_j: "archive:true"
-      }
-      execution_timeout_secs: 1800
-    }
-    builders {
-      name: "linux-android-4.0.4"
-      swarming_host: "chrome-swarming.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
@@ -60,10 +51,35 @@
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "archive:\"true\""
+        properties_j: "builder_group:\"internal.client.r8\""
+      }
+      priority: 25
+      execution_timeout_secs: 1800
+      expiration_secs: 126000
+      build_numbers: YES
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android-4.0.4"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
+      dimensions: "os:Ubuntu-16.04"
+      dimensions: "pool:luci.r8.ci"
+      recipe {
+        name: "rex"
+        cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+        cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=4.0.4\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -72,16 +88,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=4.0.4\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -90,16 +110,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=4.4.4\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -108,16 +132,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=4.4.4\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -126,16 +154,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=5.1.1\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -144,16 +176,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=5.1.1\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -162,16 +198,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=6.0.1\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -180,16 +220,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=6.0.1\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -198,16 +242,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=7.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -216,16 +264,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=7.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -234,16 +286,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=10.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -252,16 +308,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=10.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -270,16 +330,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=8.1.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -288,16 +352,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=8.1.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -306,16 +374,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=9.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -324,16 +396,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--dex_vm=9.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -342,16 +418,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--runtimes=dex-default\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -360,52 +440,64 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--runtimes=dex-default\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
       name: "linux-internal"
       swarming_host: "chrome-swarming.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "cores:8"
+      dimensions: "cores:2"
       dimensions: "cpu:x86-64"
+      dimensions: "internal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "test_options:[\"--runtimes=jdk11\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        properties_j: "builder_group:\"internal.client.r8\""
+        properties_j: "internal:\"true\""
       }
-      execution_timeout_secs: 21600
+      priority: 25
+      execution_timeout_secs: 43200
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
       name: "linux-internal_release"
       swarming_host: "chrome-swarming.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "cores:8"
+      dimensions: "cores:2"
       dimensions: "cpu:x86-64"
+      dimensions: "internal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "test_options:[\"--runtimes=jdk11\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        properties_j: "builder_group:\"internal.client.r8\""
+        properties_j: "internal:\"true\""
       }
-      execution_timeout_secs: 21600
+      priority: 25
+      execution_timeout_secs: 43200
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -414,16 +506,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--runtimes=jdk11\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -432,16 +528,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--runtimes=jdk11\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -450,16 +550,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--runtimes=jdk8\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -468,16 +572,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--runtimes=jdk8\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -486,16 +594,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--runtimes=jdk9\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -504,16 +616,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--runtimes=jdk9\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -522,16 +638,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--runtimes=none\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -540,16 +660,20 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
       recipe {
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--runtimes=none\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -564,10 +688,13 @@
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
     builders {
@@ -582,10 +709,13 @@
         name: "rex"
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
+        properties_j: "builder_group:\"internal.client.r8\""
         properties_j: "test_options:[\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
       }
+      priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
+      build_numbers: YES
       service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     }
   }
diff --git a/infra/config/global/generated/luci-milo.cfg b/infra/config/global/generated/luci-milo.cfg
index 3202e40..112e9a1 100644
--- a/infra/config/global/generated/luci-milo.cfg
+++ b/infra/config/global/generated/luci-milo.cfg
@@ -17,60 +17,10 @@
   }
   builders {
     name: "buildbucket/luci.r8.ci/archive_release"
-    category: "R8"
+    category: "R8 release"
     short_name: "archive_release"
   }
   builders {
-    name: "buildbucket/luci.r8.ci/linux-dex_default"
-    category: "R8"
-    short_name: "dex_default"
-  }
-  builders {
-    name: "buildbucket/luci.r8.ci/linux-dex_default_release"
-    category: "R8 release"
-    short_name: "dex_default"
-  }
-  builders {
-    name: "buildbucket/luci.r8.ci/linux-none"
-    category: "R8"
-    short_name: "none"
-  }
-  builders {
-    name: "buildbucket/luci.r8.ci/linux-none_release"
-    category: "R8 release"
-    short_name: "none"
-  }
-  builders {
-    name: "buildbucket/luci.r8.ci/linux-jdk8"
-    category: "R8"
-    short_name: "jdk8"
-  }
-  builders {
-    name: "buildbucket/luci.r8.ci/linux-jdk8_release"
-    category: "R8 release"
-    short_name: "jdk8"
-  }
-  builders {
-    name: "buildbucket/luci.r8.ci/linux-jdk9"
-    category: "R8"
-    short_name: "jdk9"
-  }
-  builders {
-    name: "buildbucket/luci.r8.ci/linux-jdk9_release"
-    category: "R8 release"
-    short_name: "jdk9"
-  }
-  builders {
-    name: "buildbucket/luci.r8.ci/linux-jdk11"
-    category: "R8"
-    short_name: "jdk11"
-  }
-  builders {
-    name: "buildbucket/luci.r8.ci/linux-jdk11_release"
-    category: "R8 release"
-    short_name: "jdk11"
-  }
-  builders {
     name: "buildbucket/luci.r8.ci/linux-internal"
     category: "R8"
     short_name: "internal"
@@ -78,7 +28,57 @@
   builders {
     name: "buildbucket/luci.r8.ci/linux-internal_release"
     category: "R8 release"
-    short_name: "internal"
+    short_name: "internal_release"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-dex_default"
+    category: "R8"
+    short_name: "dex_default"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-dex_default_release"
+    category: "R8 release"
+    short_name: "dex_default_release"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-none"
+    category: "R8"
+    short_name: "none"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-none_release"
+    category: "R8 release"
+    short_name: "none_release"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-jdk8"
+    category: "R8"
+    short_name: "jdk8"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-jdk8_release"
+    category: "R8 release"
+    short_name: "jdk8_release"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-jdk9"
+    category: "R8"
+    short_name: "jdk9"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-jdk9_release"
+    category: "R8 release"
+    short_name: "jdk9_release"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-jdk11"
+    category: "R8"
+    short_name: "jdk11"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-jdk11_release"
+    category: "R8 release"
+    short_name: "jdk11_release"
   }
   builders {
     name: "buildbucket/luci.r8.ci/linux-android-4.0.4"
@@ -88,7 +88,7 @@
   builders {
     name: "buildbucket/luci.r8.ci/linux-android-4.0.4_release"
     category: "R8 release"
-    short_name: "4.0.4"
+    short_name: "4.0.4_release"
   }
   builders {
     name: "buildbucket/luci.r8.ci/linux-android-4.4.4"
@@ -98,7 +98,7 @@
   builders {
     name: "buildbucket/luci.r8.ci/linux-android-4.4.4_release"
     category: "R8 release"
-    short_name: "4.4.4"
+    short_name: "4.4.4_release"
   }
   builders {
     name: "buildbucket/luci.r8.ci/linux-android-5.1.1"
@@ -108,7 +108,7 @@
   builders {
     name: "buildbucket/luci.r8.ci/linux-android-5.1.1_release"
     category: "R8 release"
-    short_name: "5.1.1"
+    short_name: "5.1.1_release"
   }
   builders {
     name: "buildbucket/luci.r8.ci/linux-android-6.0.1"
@@ -118,7 +118,7 @@
   builders {
     name: "buildbucket/luci.r8.ci/linux-android-6.0.1_release"
     category: "R8 release"
-    short_name: "6.0.1"
+    short_name: "6.0.1_release"
   }
   builders {
     name: "buildbucket/luci.r8.ci/linux-android-7.0.0"
@@ -128,7 +128,7 @@
   builders {
     name: "buildbucket/luci.r8.ci/linux-android-7.0.0_release"
     category: "R8 release"
-    short_name: "7.0.0"
+    short_name: "7.0.0_release"
   }
   builders {
     name: "buildbucket/luci.r8.ci/linux-android=8.1.0"
@@ -138,7 +138,7 @@
   builders {
     name: "buildbucket/luci.r8.ci/linux-android=8.1.0_release"
     category: "R8 release"
-    short_name: "android=8.1.0"
+    short_name: "android=8.1.0_release"
   }
   builders {
     name: "buildbucket/luci.r8.ci/linux-android=9.0.0"
@@ -148,7 +148,7 @@
   builders {
     name: "buildbucket/luci.r8.ci/linux-android=9.0.0_release"
     category: "R8 release"
-    short_name: "android=9.0.0"
+    short_name: "android=9.0.0_release"
   }
   builders {
     name: "buildbucket/luci.r8.ci/linux-android=10.0.0"
@@ -158,7 +158,7 @@
   builders {
     name: "buildbucket/luci.r8.ci/linux-android=10.0.0_release"
     category: "R8 release"
-    short_name: "android=10.0.0"
+    short_name: "android=10.0.0_release"
   }
   builders {
     name: "buildbucket/luci.r8.ci/windows"
@@ -168,6 +168,6 @@
   builders {
     name: "buildbucket/luci.r8.ci/windows_release"
     category: "R8 release"
-    short_name: "windows"
+    short_name: "windows_release"
   }
 }
diff --git a/infra/config/global/generated/luci-notify.cfg b/infra/config/global/generated/luci-notify.cfg
index 24a7816..5267938 100644
--- a/infra/config/global/generated/luci-notify.cfg
+++ b/infra/config/global/generated/luci-notify.cfg
@@ -12,6 +12,30 @@
   }
   builders {
     bucket: "ci"
+    name: "archive"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "archive_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
     name: "linux-android-4.0.4"
     repository: "https://r8.googlesource.com/r8"
   }
diff --git a/infra/config/global/generated/luci-scheduler.cfg b/infra/config/global/generated/luci-scheduler.cfg
index 72809c3..4aa3c0f 100644
--- a/infra/config/global/generated/luci-scheduler.cfg
+++ b/infra/config/global/generated/luci-scheduler.cfg
@@ -197,6 +197,11 @@
 job {
   id: "linux-internal"
   acl_sets: "ci"
+  triggering_policy {
+    kind: GREEDY_BATCHING
+    max_concurrent_invocations: 1
+    max_batch_size: 1
+  }
   buildbucket {
     server: "cr-buildbucket.appspot.com"
     bucket: "luci.r8.ci"
@@ -206,6 +211,11 @@
 job {
   id: "linux-internal_release"
   acl_sets: "ci"
+  triggering_policy {
+    kind: GREEDY_BATCHING
+    max_concurrent_invocations: 1
+    max_batch_size: 1
+  }
   buildbucket {
     server: "cr-buildbucket.appspot.com"
     bucket: "luci.r8.ci"
diff --git a/infra/config/global/main.star b/infra/config/global/main.star
index cdadb61..77d9887 100755
--- a/infra/config/global/main.star
+++ b/infra/config/global/main.star
@@ -23,9 +23,11 @@
                 acl.BUILDBUCKET_TRIGGERER,
             ],
             groups = [
-                "luci-scheduler@appspot.gserviceaccount.com",
                 "project-r8-committers"
-    ],
+            ],
+            users = [
+                "luci-scheduler@appspot.gserviceaccount.com"
+            ]
         ),
 
     ]
@@ -87,7 +89,7 @@
     "--archive_failures"
 ]
 
-def get_dimensions(windows=False, jctf=False, internal=False):
+def get_dimensions(windows=False, jctf=False, internal=False, normal=False):
   dimensions = {
     "cores" : "2" if internal else "8",
     "cpu" : "x86-64",
@@ -101,84 +103,91 @@
     dimensions["jctf"] = "true"
   if internal:
     dimensions["internal"] = "true"
+  if normal:
+    dimensions["normal"] = "true"
   return dimensions
 
+def r8_builder(name, priority=26, **kwargs):
+  release = name.endswith("release")
+  triggered = ["branch-gitiles-trigger"] if release \
+      else ["main-gitiles-trigger"]
+
+  luci.builder(
+    name = name,
+    bucket = "ci",
+    service_account = "r8-ci-builder@chops-service-accounts." +
+        "iam.gserviceaccount.com",
+    build_numbers = True,
+    swarming_tags = ["vpython:native-python-wrapper"],
+    notifies = ["r8-failures"],
+    priority = priority,
+    triggered_by = triggered,
+    executable = "rex",
+    **kwargs
+  )
+  category = "R8 release" if release else "R8"
+  builder_view(name, category, name.split("-")[-1])
+
 def r8_tester(name,
     test_options,
-    dimensions=None,
-    execution_timeout=time.hour * 6,
-    expiration_timeout=time.hour * 35):
-  dimensions = dimensions if dimensions else get_dimensions()
-  luci.builder(
-      name = name,
-      bucket = "ci",
-      service_account = "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com",
-      swarming_tags = ["vpython:native-python-wrapper"],
-      execution_timeout=execution_timeout,
-      expiration_timeout=expiration_timeout,
-      executable = "rex",
-      dimensions = dimensions,
-      triggered_by = ["main-gitiles-trigger"],
-      properties = {
-          "test_options" : test_options
-      },
-      notifies = ["r8-failures"]
-  )
-  builder_view(name, "R8", name.split("-")[-1])
-
-  # Branch version
-  release_name = name + "_release"
-  luci.builder(
-      name = release_name,
-      bucket = "ci",
-      service_account = "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com",
-      swarming_tags = ["vpython:native-python-wrapper"],
-      execution_timeout=execution_timeout,
-      expiration_timeout=expiration_timeout,
-      executable = "rex",
-      dimensions = dimensions,
-      triggered_by = ["branch-gitiles-trigger"],
-      properties = {
-          "test_options" : test_options
-      },
-      notifies = ["r8-failures"]
-  )
-  builder_view(release_name, "R8 release", name.split("-")[-1])
+    dimensions = None,
+    execution_timeout = time.hour * 6,
+    expiration_timeout = time.hour * 35):
+  dimensions = dimensions if dimensions else get_dimensions(normal=True)
+  for name in [name, name + "_release"]:
+    r8_builder(
+        name = name,
+        execution_timeout=execution_timeout,
+        expiration_timeout=expiration_timeout,
+        dimensions = dimensions,
+        properties = {
+            "test_options" : test_options,
+            "builder_group" : "internal.client.r8"
+        }
+    )
 
 def r8_tester_with_default(name, test_options, dimensions=None):
   r8_tester(name, test_options + common_test_options, dimensions)
 
-luci.builder(
-    name = "archive",
-    bucket = "ci",
-    dimensions = get_dimensions(),
-    triggered_by = ["main-gitiles-trigger"],
-    executable = "rex",
-    execution_timeout = time.minute * 30,
-      triggering_policy = scheduler.policy(
-        kind = scheduler.GREEDY_BATCHING_KIND,
-        max_batch_size = 1,
-        max_concurrent_invocations = 3
-    ),
-    properties = {"archive": True}
-)
-builder_view("archive", "R8", "archive")
+def archivers():
+  for name in ["archive", "archive_release"]:
+    r8_builder(
+        name,
+        dimensions = get_dimensions(),
+        triggering_policy = scheduler.policy(
+            kind = scheduler.GREEDY_BATCHING_KIND,
+            max_batch_size = 1,
+            max_concurrent_invocations = 3
+        ),
+        priority = 25,
+        properties = {
+            "archive": "true",
+            "builder_group" : "internal.client.r8"
+        },
+        execution_timeout = time.minute * 30,
+        expiration_timeout = time.hour * 35,
+    )
+archivers()
 
-luci.builder(
-    name = "archive_release",
-    bucket = "ci",
-    dimensions = get_dimensions(),
-    triggered_by = ["branch-gitiles-trigger"],
-    execution_timeout = time.minute * 30,
-    executable = "rex",
-    triggering_policy = scheduler.policy(
-        kind = scheduler.GREEDY_BATCHING_KIND,
-        max_batch_size = 1,
-        max_concurrent_invocations = 3
-    ),
-    properties = {"archive": True}
-)
-builder_view("archive_release", "R8", "archive_release")
+def internal():
+  for name in ["linux-internal", "linux-internal_release"]:
+    r8_builder(
+        name,
+        dimensions = get_dimensions(internal=True),
+        triggering_policy = scheduler.policy(
+            kind = scheduler.GREEDY_BATCHING_KIND,
+            max_batch_size = 1,
+            max_concurrent_invocations = 1
+        ),
+        priority = 25,
+        properties = {
+            "internal": "true",
+            "builder_group" : "internal.client.r8"
+        },
+        execution_timeout = time.hour * 12,
+        expiration_timeout = time.hour * 35,
+    )
+internal()
 
 r8_tester_with_default("linux-dex_default", ["--runtimes=dex-default"])
 r8_tester_with_default("linux-none", ["--runtimes=none"])
@@ -186,8 +195,6 @@
 r8_tester_with_default("linux-jdk9", ["--runtimes=jdk9"])
 r8_tester_with_default("linux-jdk11", ["--runtimes=jdk11"])
 
-r8_tester_with_default("linux-internal", ["--runtimes=jdk11"])
-
 r8_tester_with_default("linux-android-4.0.4",
     ["--dex_vm=4.0.4", "--all_tests"])
 r8_tester_with_default("linux-android-4.4.4",
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index 19d4a98..2906011 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -162,6 +162,8 @@
               code,
               false,
               CfVersion.V1_6,
+              AndroidApiLevel.UNKNOWN,
+              AndroidApiLevel.UNKNOWN,
               false);
       if (method.isStatic() || method.isDirectMethod()) {
         directMethods.add(throwingMethod);
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index c2ee174..6f2675f 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -106,6 +106,7 @@
 import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer;
 import com.android.tools.r8.synthesis.SyntheticFinalization;
 import com.android.tools.r8.synthesis.SyntheticItems;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.CfgPrinter;
 import com.android.tools.r8.utils.CollectionUtils;
@@ -370,7 +371,6 @@
         assert appView.rootSet().verifyKeptMethodsAreTargetedAndLive(appViewWithLiveness.appInfo());
         assert appView.rootSet().verifyKeptTypesAreLive(appViewWithLiveness.appInfo());
         assert appView.rootSet().verifyKeptItemsAreKept(appView);
-
         appView.rootSet().checkAllRulesAreUsed(options);
 
         if (options.proguardSeedsConsumer != null) {
@@ -392,7 +392,7 @@
           // Build enclosing information and type-parameter information before pruning.
           // TODO(b/187922482): Only consider referenced classes.
           GenericSignatureContextBuilder genericContextBuilder =
-              GenericSignatureContextBuilder.create(appView.appInfo().classes());
+              GenericSignatureContextBuilder.create(appView);
 
           // Compute if all signatures are valid before modifying them.
           GenericSignatureCorrectnessHelper.createForInitialCheck(appView, genericContextBuilder)
@@ -432,6 +432,7 @@
       AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
 
       assert verifyNoJarApplicationReaders(appView.appInfo().classes());
+      assert appView.checkForTesting(() -> allReferencesAssignedApiLevel(appViewWithLiveness));
       // Build conservative main dex content after first round of tree shaking. This is used
       // by certain optimizations to avoid introducing additional class references into main dex
       // classes, as that can cause the final number of main dex methods to grow.
@@ -530,6 +531,7 @@
 
       // None of the optimizations above should lead to the creation of type lattice elements.
       assert appView.dexItemFactory().verifyNoCachedTypeElements();
+      assert appView.checkForTesting(() -> allReferencesAssignedApiLevel(appViewWithLiveness));
 
       // Collect switch maps and ordinals maps.
       if (options.enableEnumSwitchMapRemoval) {
@@ -615,7 +617,7 @@
                     DefaultTreePrunerConfiguration.getInstance());
 
             GenericSignatureContextBuilder genericContextBuilder =
-                GenericSignatureContextBuilder.create(appView.appInfo().classes());
+                GenericSignatureContextBuilder.create(appView);
 
             TreePruner pruner = new TreePruner(appViewWithLiveness, treePrunerConfiguration);
             DirectMappedDexApplication application = pruner.run(executorService);
@@ -663,8 +665,7 @@
             assert appView.checkForTesting(
                     () ->
                         GenericSignatureCorrectnessHelper.createForVerification(
-                                appView,
-                                GenericSignatureContextBuilder.create(appView.appInfo().classes()))
+                                appView, GenericSignatureContextBuilder.create(appView))
                             .run(appView.appInfo().classes())
                             .isValid())
                 : "Could not validate generic signatures";
@@ -748,7 +749,7 @@
       appView.dexItemFactory().clearTypeElementsCache();
 
       GenericSignatureContextBuilder genericContextBuilderBeforeFinalMerging =
-          GenericSignatureContextBuilder.create(appView.appInfo().classes());
+          GenericSignatureContextBuilder.create(appView);
 
       // Run horizontal class merging. This runs even if shrinking is disabled to ensure synthetics
       // are always merged.
@@ -839,8 +840,7 @@
               () ->
                   !options.isShrinking()
                       || GenericSignatureCorrectnessHelper.createForVerification(
-                              appView,
-                              GenericSignatureContextBuilder.create(appView.appInfo().classes()))
+                              appView, GenericSignatureContextBuilder.create(appView))
                           .run(appView.appInfo().classes())
                           .isValid())
           : "Could not validate generic signatures";
@@ -872,6 +872,27 @@
     }
   }
 
+  private static boolean allReferencesAssignedApiLevel(AppView<?> appView) {
+    if (!appView.options().apiModelingOptions().checkAllApiReferencesAreSet) {
+      return true;
+    }
+    // This will return false if we find anything in the library which is not modeled.
+    appView
+        .appInfo()
+        .classes()
+        .forEach(
+            clazz -> {
+              if (appView.options().apiModelingOptions().enableApiCallerIdentification) {
+                assert clazz.getMembersApiReferenceLevel(appView) != AndroidApiLevel.UNKNOWN
+                    : "Every member should have been analyzed";
+              } else {
+                assert clazz.getMembersApiReferenceLevel(appView) == AndroidApiLevel.UNKNOWN
+                    : "Every member should have level UNKNOWN";
+              }
+            });
+    return true;
+  }
+
   private void performInitialMainDexTracing(
       AppView<AppInfoWithClassHierarchy> appView, ExecutorService executorService)
       throws ExecutionException {
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
index f2502e2..e3fa030 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
@@ -69,7 +69,9 @@
 
   public AndroidApiLevel lookup(DexReference reference) {
     DexType contextType = reference.getContextType();
-    assert !contextType.isArrayType();
+    if (contextType.isArrayType()) {
+      return lookup(contextType.toBaseType(appView.dexItemFactory()));
+    }
     if (contextType.isPrimitiveType() || contextType.isVoidType()) {
       return AndroidApiLevel.B;
     }
diff --git a/src/main/java/com/android/tools/r8/graph/ClassDefinition.java b/src/main/java/com/android/tools/r8/graph/ClassDefinition.java
index da0f128..589dd76 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassDefinition.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassDefinition.java
@@ -28,11 +28,6 @@
     return true;
   }
 
-  @Override
-  default ClassDefinition asClass() {
-    return this;
-  }
-
   boolean isClasspathClass();
 
   DexClasspathClass asClasspathClass();
@@ -40,8 +35,4 @@
   boolean isLibraryClass();
 
   DexLibraryClass asLibraryClass();
-
-  boolean isProgramClass();
-
-  DexProgramClass asProgramClass();
 }
diff --git a/src/main/java/com/android/tools/r8/graph/ClasspathMember.java b/src/main/java/com/android/tools/r8/graph/ClasspathMember.java
index 8fad10f..1919491 100644
--- a/src/main/java/com/android/tools/r8/graph/ClasspathMember.java
+++ b/src/main/java/com/android/tools/r8/graph/ClasspathMember.java
@@ -7,6 +7,7 @@
 public interface ClasspathMember<D extends DexEncodedMember<D, R>, R extends DexMember<D, R>>
     extends ClasspathDefinition {
 
+  @Override
   D getDefinition();
 
   DexClasspathClass getHolder();
diff --git a/src/main/java/com/android/tools/r8/graph/Definition.java b/src/main/java/com/android/tools/r8/graph/Definition.java
index 7e42398..b3dcc3a 100644
--- a/src/main/java/com/android/tools/r8/graph/Definition.java
+++ b/src/main/java/com/android/tools/r8/graph/Definition.java
@@ -24,8 +24,12 @@
 
   ProgramDerivedContext asProgramDerivedContext(ProgramDerivedContext witness);
 
+  AccessFlags<?> getAccessFlags();
+
   DexType getContextType();
 
+  DexDefinition getDefinition();
+
   Origin getOrigin();
 
   DexReference getReference();
@@ -34,7 +38,7 @@
     return false;
   }
 
-  default ClassDefinition asClass() {
+  default DexClass asClass() {
     return null;
   }
 
@@ -46,6 +50,14 @@
     return null;
   }
 
+  default boolean isMember() {
+    return !isClass();
+  }
+
+  default DexClassAndMember<?, ?> asMember() {
+    return null;
+  }
+
   default boolean isMethod() {
     return false;
   }
@@ -54,6 +66,54 @@
     return null;
   }
 
+  default boolean isClasspathField() {
+    return false;
+  }
+
+  default ClasspathField asClasspathField() {
+    return null;
+  }
+
+  default boolean isClasspathMember() {
+    return false;
+  }
+
+  default boolean isClasspathMethod() {
+    return false;
+  }
+
+  default ClasspathMethod asClasspathMethod() {
+    return null;
+  }
+
+  default boolean isLibraryField() {
+    return false;
+  }
+
+  default LibraryField asLibraryField() {
+    return null;
+  }
+
+  default boolean isLibraryMember() {
+    return false;
+  }
+
+  default boolean isLibraryMethod() {
+    return false;
+  }
+
+  default LibraryMethod asLibraryMethod() {
+    return null;
+  }
+
+  default boolean isProgramClass() {
+    return false;
+  }
+
+  default DexProgramClass asProgramClass() {
+    return null;
+  }
+
   default boolean isProgramDefinition() {
     return false;
   }
@@ -61,4 +121,28 @@
   default ProgramDefinition asProgramDefinition() {
     return null;
   }
+
+  default boolean isProgramField() {
+    return false;
+  }
+
+  default ProgramField asProgramField() {
+    return null;
+  }
+
+  default boolean isProgramMember() {
+    return false;
+  }
+
+  default ProgramMember<?, ?> asProgramMember() {
+    return null;
+  }
+
+  default boolean isProgramMethod() {
+    return false;
+  }
+
+  default ProgramMethod asProgramMethod() {
+    return null;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 50362b0..f3937c2 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -676,6 +676,11 @@
   }
 
   @Override
+  public DexClass asClass() {
+    return this;
+  }
+
+  @Override
   public boolean isDexClass() {
     return true;
   }
@@ -737,6 +742,11 @@
   }
 
   @Override
+  public DexClass getDefinition() {
+    return this;
+  }
+
+  @Override
   public Origin getOrigin() {
     return this.origin;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndField.java b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
index 2c78b93..30179b3 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
@@ -55,27 +55,8 @@
     return this;
   }
 
-  public boolean isClasspathField() {
-    return false;
-  }
-
-  public ClasspathField asClasspathField() {
-    return null;
-  }
-
-  public boolean isLibraryField() {
-    return false;
-  }
-
-  public LibraryField asLibraryField() {
-    return null;
-  }
-
-  public boolean isProgramField() {
-    return false;
-  }
-
-  public ProgramField asProgramField() {
-    return null;
+  @Override
+  public DexClassAndField asMember() {
+    return this;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
index 52cb7a9..f82bcbc 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
@@ -22,8 +22,6 @@
     this.definition = definition;
   }
 
-  public abstract AccessFlags<?> getAccessFlags();
-
   public final DexAnnotationSet getAnnotations() {
     return definition.annotations();
   }
@@ -41,6 +39,7 @@
     return holder.type;
   }
 
+  @Override
   public D getDefinition() {
     return definition;
   }
@@ -63,18 +62,6 @@
     return holder.origin;
   }
 
-  public boolean isClasspathMember() {
-    return false;
-  }
-
-  public boolean isLibraryMember() {
-    return false;
-  }
-
-  public boolean isProgramMember() {
-    return false;
-  }
-
   public String toSourceString() {
     return getReference().toSourceString();
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
index 2f18405..b39a1a7 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
 import com.android.tools.r8.references.MethodReference;
+import java.util.function.Consumer;
 
 public abstract class DexClassAndMethod extends DexClassAndMember<DexEncodedMethod, DexMethod>
     implements LookupTarget {
@@ -98,31 +99,18 @@
   }
 
   @Override
+  public DexClassAndMethod asMember() {
+    return this;
+  }
+
+  @Override
   public DexClassAndMethod asMethod() {
     return this;
   }
 
-  public boolean isClasspathMethod() {
-    return false;
-  }
-
-  public ClasspathMethod asClasspathMethod() {
-    return null;
-  }
-
-  public boolean isLibraryMethod() {
-    return false;
-  }
-
-  public LibraryMethod asLibraryMethod() {
-    return null;
-  }
-
-  public boolean isProgramMethod() {
-    return false;
-  }
-
-  public ProgramMethod asProgramMethod() {
-    return null;
+  @Override
+  public void accept(
+      Consumer<DexClassAndMethod> methodConsumer, Consumer<LookupLambdaTarget> lambdaConsumer) {
+    methodConsumer.accept(this);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexDefinition.java b/src/main/java/com/android/tools/r8/graph/DexDefinition.java
index 25c339e..9b69a2f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDefinition.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDefinition.java
@@ -58,6 +58,10 @@
         annotations().rewrite(annotation -> rewriter.apply(annotation, AnnotatedKind.from(this))));
   }
 
+  public DexClass asClass() {
+    return null;
+  }
+
   public boolean isDexClass() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 5049ee4..6daff01 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -6,6 +6,7 @@
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
 import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.MIN_API_LEVEL;
 
 import com.android.tools.r8.dex.MixedSectionCollection;
 import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
@@ -44,7 +45,7 @@
   /** Generic signature information if the attribute is present in the input */
   private FieldTypeSignature genericSignature;
 
-  private FieldOptimizationInfo optimizationInfo = DefaultFieldOptimizationInfo.getInstance();
+  private FieldOptimizationInfo optimizationInfo;
   private KotlinFieldLevelInfo kotlinMemberInfo = getNoKotlinInfo();
 
   private static void specify(StructuralSpecification<DexEncodedField, ?> spec) {
@@ -77,7 +78,15 @@
       DexAnnotationSet annotations,
       DexValue staticValue,
       boolean deprecated) {
-    this(field, accessFlags, genericSignature, annotations, staticValue, deprecated, false);
+    this(
+        field,
+        accessFlags,
+        genericSignature,
+        annotations,
+        staticValue,
+        deprecated,
+        false,
+        AndroidApiLevel.UNKNOWN);
   }
 
   public DexEncodedField(
@@ -87,12 +96,22 @@
       DexAnnotationSet annotations,
       DexValue staticValue,
       boolean deprecated,
-      boolean d8R8Synthesized) {
+      boolean d8R8Synthesized,
+      AndroidApiLevel apiLevel) {
     super(field, annotations, d8R8Synthesized);
     this.accessFlags = accessFlags;
     this.staticValue = staticValue;
     this.deprecated = deprecated;
     this.genericSignature = genericSignature;
+    if (apiLevel == AndroidApiLevel.UNKNOWN) {
+      optimizationInfo = DefaultFieldOptimizationInfo.getInstance();
+    } else if (apiLevel == MIN_API_LEVEL) {
+      optimizationInfo = DefaultFieldOptimizationWithMinApiInfo.getInstance();
+    } else {
+      MutableFieldOptimizationInfo optimizationInfo = new MutableFieldOptimizationInfo();
+      this.optimizationInfo = optimizationInfo;
+      optimizationInfo.setApiReferenceLevelForDefinition(apiLevel);
+    }
     assert genericSignature != null;
     assert GenericSignatureUtils.verifyNoDuplicateGenericDefinitions(genericSignature, annotations);
   }
@@ -448,7 +467,8 @@
               annotations,
               staticValue,
               deprecated,
-              d8R8Synthesized);
+              d8R8Synthesized,
+              AndroidApiLevel.UNKNOWN);
       dexEncodedField.optimizationInfo = optimizationInfo;
       buildConsumer.accept(dexEncodedField);
       return dexEncodedField;
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index d3af4ee..c6913f8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -11,6 +11,7 @@
 import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_NOT_INLINING_CANDIDATE;
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.MIN_API_LEVEL;
 import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
 
 import com.android.tools.r8.cf.CfVersion;
@@ -258,7 +259,9 @@
         parameterAnnotationsList,
         code,
         false,
-        null);
+        null,
+        AndroidApiLevel.UNKNOWN,
+        AndroidApiLevel.UNKNOWN);
   }
 
   public DexEncodedMethod(
@@ -277,7 +280,9 @@
         parameterAnnotationsList,
         code,
         d8R8Synthesized,
-        null);
+        null,
+        AndroidApiLevel.UNKNOWN,
+        AndroidApiLevel.UNKNOWN);
   }
 
   public DexEncodedMethod(
@@ -288,7 +293,9 @@
       ParameterAnnotationsList parameterAnnotationsList,
       Code code,
       boolean d8R8Synthesized,
-      CfVersion classFileVersion) {
+      CfVersion classFileVersion,
+      AndroidApiLevel apiLevelForDefinition,
+      AndroidApiLevel apiLevelForCode) {
     this(
         method,
         accessFlags,
@@ -298,6 +305,8 @@
         code,
         d8R8Synthesized,
         classFileVersion,
+        apiLevelForDefinition,
+        apiLevelForCode,
         false);
   }
 
@@ -310,6 +319,8 @@
       Code code,
       boolean d8R8Synthesized,
       CfVersion classFileVersion,
+      AndroidApiLevel apiLevelForDefinition,
+      AndroidApiLevel apiLevelForCode,
       boolean deprecated) {
     super(method, annotations, d8R8Synthesized);
     this.accessFlags = accessFlags;
@@ -318,6 +329,18 @@
     this.parameterAnnotationsList = parameterAnnotationsList;
     this.code = code;
     this.classFileVersion = classFileVersion;
+    if (apiLevelForDefinition == AndroidApiLevel.UNKNOWN
+        && apiLevelForCode == AndroidApiLevel.UNKNOWN) {
+      optimizationInfo = DefaultMethodOptimizationInfo.getInstance();
+    } else if (apiLevelForDefinition == MIN_API_LEVEL && apiLevelForCode == MIN_API_LEVEL) {
+      optimizationInfo = DefaultMethodOptimizationWithMinApiInfo.getInstance();
+    } else {
+      MutableMethodOptimizationInfo optimizationInfo =
+          DefaultMethodOptimizationInfo.getInstance().toMutableOptimizationInfo();
+      optimizationInfo.setApiReferenceLevelForDefinition(apiLevelForDefinition);
+      optimizationInfo.setApiReferenceLevelForCode(apiLevelForCode);
+      this.optimizationInfo = optimizationInfo;
+    }
     assert accessFlags != null;
     assert code == null || !shouldNotHaveCode();
     assert parameterAnnotationsList != null;
@@ -1714,7 +1737,9 @@
               parameterAnnotations,
               code,
               d8R8Synthesized,
-              classFileVersion);
+              classFileVersion,
+              AndroidApiLevel.UNKNOWN,
+              AndroidApiLevel.UNKNOWN);
       result.setKotlinMemberInfo(kotlinInfo);
       result.compilationState = compilationState;
       result.optimizationInfo = optimizationInfo;
diff --git a/src/main/java/com/android/tools/r8/graph/DexMember.java b/src/main/java/com/android/tools/r8/graph/DexMember.java
index bffc842..2fa9753 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMember.java
@@ -65,7 +65,10 @@
 
   public AndroidApiLevel computeApiLevelForReferencedTypes(
       AppView<?> appView, BiFunction<DexReference, AndroidApiLevel, AndroidApiLevel> computeMax) {
-    AndroidApiLevel computedLevel = appView.options().minApiLevel;
+    AndroidApiLevel computedLevel =
+        appView.options().apiModelingOptions().enableApiCallerIdentification
+            ? appView.options().minApiLevel
+            : AndroidApiLevel.UNKNOWN;
     for (DexType type : getReferencedBaseTypes(appView.dexItemFactory())) {
       computedLevel = computeMax.apply(type, computedLevel);
     }
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 90841e1..8a3f39a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.graph;
 
 import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabled;
 import static com.google.common.base.Predicates.alwaysTrue;
 
 import com.android.tools.r8.ProgramResource;
@@ -823,22 +824,27 @@
   }
 
   public AndroidApiLevel getApiReferenceLevel(
-      AndroidApiLevel minApiLevel,
+      AppView<?> appView,
       BiFunction<DexReference, AndroidApiLevel, AndroidApiLevel> apiLevelLookup) {
     // The api level of a class is the max level of it's members, super class and interfaces.
-    AndroidApiLevel computedApiLevel = minApiLevel;
+    AndroidApiLevel computedApiLevel = getApiLevelIfEnabled(appView, Function.identity());
     for (DexType superType : allImmediateSupertypes()) {
       computedApiLevel = apiLevelLookup.apply(superType, computedApiLevel);
       if (computedApiLevel == AndroidApiLevel.UNKNOWN) {
         return AndroidApiLevel.UNKNOWN;
       }
     }
+    return computedApiLevel.max(getMembersApiReferenceLevel(appView));
+  }
+
+  public AndroidApiLevel getMembersApiReferenceLevel(AppView<?> appView) {
+    AndroidApiLevel memberLevel = getApiLevelIfEnabled(appView, Function.identity());
     for (DexEncodedMember<?, ?> member : members()) {
-      computedApiLevel = member.getApiReferenceLevel(computedApiLevel);
-      if (computedApiLevel == AndroidApiLevel.UNKNOWN) {
+      memberLevel = memberLevel.max(getApiLevelIfEnabled(appView, member::getApiReferenceLevel));
+      if (memberLevel == AndroidApiLevel.UNKNOWN) {
         return AndroidApiLevel.UNKNOWN;
       }
     }
-    return computedApiLevel;
+    return memberLevel;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java
index 1b1eabf..3492c06 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java
@@ -131,7 +131,15 @@
     this.enclosingInfo = enclosingInfo;
   }
 
-  public static GenericSignatureContextBuilder create(Collection<DexProgramClass> programClasses) {
+  public static GenericSignatureContextBuilder create(AppView<?> appView) {
+    return create(appView, appView.appInfo().classes());
+  }
+
+  public static GenericSignatureContextBuilder create(
+      AppView<?> appView, Collection<DexProgramClass> programClasses) {
+    if (!appView.options().parseSignatureAttribute()) {
+      return null;
+    }
     Map<DexReference, TypeParameterSubstitutions> formalsInfo = new IdentityHashMap<>();
     Map<DexReference, DexReference> enclosingInfo = new IdentityHashMap<>();
     programClasses.forEach(
@@ -187,7 +195,7 @@
         workList.addIfNotSeen(outer.asProgramClass());
       }
     }
-    return create(workList.getSeenSet());
+    return create(appView, workList.getSeenSet());
   }
 
   public TypeParameterContext computeTypeParameterContext(
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
index 1946512..d8c3142 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
@@ -21,6 +21,9 @@
 import com.android.tools.r8.graph.GenericSignature.ReturnType;
 import com.android.tools.r8.graph.GenericSignature.TypeSignature;
 import com.android.tools.r8.graph.GenericSignatureContextBuilder.TypeParameterContext;
+import com.android.tools.r8.shaking.KeepClassInfo;
+import com.android.tools.r8.shaking.KeepFieldInfo;
+import com.android.tools.r8.shaking.KeepMethodInfo;
 import com.android.tools.r8.utils.ListUtils;
 import java.util.List;
 import java.util.function.Consumer;
@@ -101,7 +104,8 @@
   }
 
   public SignatureEvaluationResult run(List<DexProgramClass> programClasses) {
-    if (appView.options().disableGenericSignatureValidation) {
+    if (appView.options().disableGenericSignatureValidation
+        || !appView.options().parseSignatureAttribute()) {
       return VALID;
     }
     SignatureEvaluationResult evaluationResult = VALID;
@@ -112,7 +116,8 @@
   }
 
   public SignatureEvaluationResult evaluateSignaturesForClass(DexProgramClass clazz) {
-    if (appView.options().disableGenericSignatureValidation) {
+    if (appView.options().disableGenericSignatureValidation
+        || !appView.options().parseSignatureAttribute()) {
       return VALID;
     }
 
@@ -125,7 +130,12 @@
     SignatureEvaluationResult result =
         genericSignatureContextEvaluator.evaluateClassSignatureForContext(typeParameterContext);
     if (result.isInvalid() && mode.clearIfInvalid()) {
-      if (appView.hasLiveness() && appView.getKeepInfo().getClassInfo(clazz).isPinned()) {
+      // Only report info messages for classes that are kept explicitly. This is to ensure we do not
+      // spam the developer with messages they can do nothing about.
+      KeepClassInfo classInfo = appView.getKeepInfo().getClassInfo(clazz);
+      if (appView.hasLiveness() && !classInfo.isShrinkingAllowed(appView.options())) {
+        // If/when this no longer holds it should be moved into the condition.
+        assert !classInfo.isSignatureAttributeRemovalAllowed(appView.options());
         appView
             .options()
             .reporter
@@ -147,8 +157,13 @@
                       genericSignatureContextEvaluator.visitMethodSignature(
                           methodSignature, typeParameterContext),
                   invalidResult -> {
+                    // Only report info messages for methods that are kept explicitly. This is to
+                    // ensure we do not spam the developer with messages they can do nothing about.
+                    KeepMethodInfo methodInfo = appView.getKeepInfo().getMethodInfo(method, clazz);
                     if (appView.hasLiveness()
-                        && appView.getKeepInfo().getMethodInfo(method, clazz).isPinned()) {
+                        && !methodInfo.isShrinkingAllowed(appView.options())) {
+                      // If/when this no longer holds it should be moved into the condition.
+                      assert !methodInfo.isSignatureAttributeRemovalAllowed(appView.options());
                       appView
                           .options()
                           .reporter
@@ -171,8 +186,12 @@
                       genericSignatureContextEvaluator.visitFieldTypeSignature(
                           fieldSignature, typeParameterContext),
                   invalidResult -> {
-                    if (appView.hasLiveness()
-                        && appView.getKeepInfo().getFieldInfo(field, clazz).isPinned()) {
+                    KeepFieldInfo fieldInfo = appView.getKeepInfo().getFieldInfo(field, clazz);
+                    // Only report info messages for fields that are kept explicitly. This is to
+                    // ensure we do not spam the developer with messages they can do nothing about.
+                    if (appView.hasLiveness() && !fieldInfo.isShrinkingAllowed(appView.options())) {
+                      // If/when this no longer holds it should be moved into the condition.
+                      assert !fieldInfo.isSignatureAttributeRemovalAllowed(appView.options());
                       appView
                           .options()
                           .reporter
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 0b179ac..55482fc 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -38,6 +38,7 @@
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.synthesis.SyntheticMarker;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AsmUtils;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.ExceptionUtils;
@@ -381,9 +382,11 @@
       assert superName != null || name.equals(Constants.JAVA_LANG_OBJECT_NAME);
       superType = superName == null ? null : application.getTypeFromName(superName);
       this.interfaces = application.getTypeListFromNames(interfaces);
-      classSignature =
-          GenericSignature.parseClassSignature(
-              name, signature, origin, application.getFactory(), application.options.reporter);
+      if (application.options.parseSignatureAttribute()) {
+        classSignature =
+            GenericSignature.parseClassSignature(
+                name, signature, origin, application.getFactory(), application.options.reporter);
+      }
     }
 
     @Override
@@ -620,7 +623,7 @@
     private final String name;
     private final String desc;
     private final Object value;
-    private FieldTypeSignature fieldSignature;
+    private final FieldTypeSignature fieldSignature;
     private List<DexAnnotation> annotations = null;
 
     public CreateFieldVisitor(
@@ -637,12 +640,14 @@
       this.desc = desc;
       this.value = value;
       this.fieldSignature =
-          GenericSignature.parseFieldTypeSignature(
-              name,
-              signature,
-              parent.origin,
-              parent.application.getFactory(),
-              parent.application.options.reporter);
+          parent.application.options.parseSignatureAttribute()
+              ? GenericSignature.parseFieldTypeSignature(
+                  name,
+                  signature,
+                  parent.origin,
+                  parent.application.getFactory(),
+                  parent.application.options.reporter)
+              : FieldTypeSignature.noSignature();
     }
 
     @Override
@@ -771,12 +776,14 @@
             values, parent.application.getFactory()));
       }
       genericSignature =
-          GenericSignature.parseMethodSignature(
-              name,
-              signature,
-              parent.origin,
-              parent.application.getFactory(),
-              parent.application.options.reporter);
+          parent.application.options.parseSignatureAttribute()
+              ? GenericSignature.parseMethodSignature(
+                  name,
+                  signature,
+                  parent.origin,
+                  parent.application.getFactory(),
+                  parent.application.options.reporter)
+              : MethodTypeSignature.noSignature();
     }
 
     @Override
@@ -908,6 +915,8 @@
               code,
               false,
               parent.version,
+              AndroidApiLevel.UNKNOWN,
+              AndroidApiLevel.UNKNOWN,
               deprecated);
       Wrapper<DexMethod> signature = MethodSignatureEquivalence.get().wrap(method);
       if (parent.methodSignatures.add(signature)) {
diff --git a/src/main/java/com/android/tools/r8/graph/LibraryMember.java b/src/main/java/com/android/tools/r8/graph/LibraryMember.java
index bf6bb03..b887324 100644
--- a/src/main/java/com/android/tools/r8/graph/LibraryMember.java
+++ b/src/main/java/com/android/tools/r8/graph/LibraryMember.java
@@ -7,6 +7,7 @@
 public interface LibraryMember<D extends DexEncodedMember<D, R>, R extends DexMember<D, R>>
     extends LibraryDefinition {
 
+  @Override
   D getDefinition();
 
   DexLibraryClass getHolder();
diff --git a/src/main/java/com/android/tools/r8/graph/LookupLambdaTarget.java b/src/main/java/com/android/tools/r8/graph/LookupLambdaTarget.java
index b41ef8f..12eeddc 100644
--- a/src/main/java/com/android/tools/r8/graph/LookupLambdaTarget.java
+++ b/src/main/java/com/android/tools/r8/graph/LookupLambdaTarget.java
@@ -4,8 +4,10 @@
 package com.android.tools.r8.graph;
 
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
+import java.util.function.Consumer;
 
 public class LookupLambdaTarget implements LookupTarget {
+
   private final LambdaDescriptor lambda;
   private final DexClassAndMethod method;
 
@@ -26,6 +28,12 @@
     return this;
   }
 
+  @Override
+  public void accept(
+      Consumer<DexClassAndMethod> methodConsumer, Consumer<LookupLambdaTarget> lambdaConsumer) {
+    lambdaConsumer.accept(this);
+  }
+
   public DexClassAndMethod getImplementationMethod() {
     return method;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/LookupTarget.java b/src/main/java/com/android/tools/r8/graph/LookupTarget.java
index 6966a44..cc0d574 100644
--- a/src/main/java/com/android/tools/r8/graph/LookupTarget.java
+++ b/src/main/java/com/android/tools/r8/graph/LookupTarget.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
+import java.util.function.Consumer;
+
 public interface LookupTarget {
   default boolean isMethodTarget() {
     return false;
@@ -19,4 +21,7 @@
   default LookupLambdaTarget asLambdaTarget() {
     return null;
   }
+
+  void accept(
+      Consumer<DexClassAndMethod> methodConsumer, Consumer<LookupLambdaTarget> lambdaConsumer);
 }
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java b/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
index c1dedd5..b36e87c 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
@@ -19,6 +19,16 @@
   }
 
   @Override
+  default ProgramField asField() {
+    return null;
+  }
+
+  @Override
+  default ProgramMethod asMethod() {
+    return null;
+  }
+
+  @Override
   default ProgramDerivedContext asProgramDerivedContext(ProgramDerivedContext witness) {
     return this;
   }
@@ -34,18 +44,6 @@
 
   DexProgramClass getContextClass();
 
-  AccessFlags<?> getAccessFlags();
-
-  DexDefinition getDefinition();
-
-  default boolean isProgramClass() {
-    return false;
-  }
-
-  default DexProgramClass asProgramClass() {
-    return null;
-  }
-
   @Override
   default boolean isProgramDefinition() {
     return true;
@@ -55,28 +53,4 @@
   default ProgramDefinition asProgramDefinition() {
     return this;
   }
-
-  default boolean isProgramField() {
-    return false;
-  }
-
-  default ProgramField asProgramField() {
-    return null;
-  }
-
-  default boolean isProgramMember() {
-    return false;
-  }
-
-  default ProgramMember<?, ?> asProgramMember() {
-    return null;
-  }
-
-  default boolean isProgramMethod() {
-    return false;
-  }
-
-  default ProgramMethod asProgramMethod() {
-    return null;
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramField.java b/src/main/java/com/android/tools/r8/graph/ProgramField.java
index aec6be0..d53cb1c 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramField.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramField.java
@@ -38,6 +38,11 @@
   }
 
   @Override
+  public ProgramField asField() {
+    return this;
+  }
+
+  @Override
   public ProgramField asProgramField() {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index 5faf268..a34b49d 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -83,6 +83,11 @@
   }
 
   @Override
+  public ProgramMethod asMethod() {
+    return this;
+  }
+
+  @Override
   public ProgramMethod asProgramMethod() {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
index 32c9420..b4615df 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.DexEncodedMember;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMember;
+import com.android.tools.r8.graph.LookupTarget;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -59,6 +60,27 @@
     setApiLevelForCode(method.getDefinition(), registry.getMaxApiReferenceLevel());
   }
 
+  @Override
+  public void notifyMarkMethodAsTargeted(ProgramMethod method) {
+    setApiLevelForMemberDefinition(method.getDefinition(), minApiLevel);
+  }
+
+  @Override
+  public void notifyMarkFieldAsReachable(ProgramField field) {
+    setApiLevelForMemberDefinition(field.getDefinition(), minApiLevel);
+  }
+
+  @Override
+  public void notifyMarkVirtualDispatchTargetAsLive(LookupTarget target) {
+    target.accept(
+        dexClassAndMethod -> {
+          setApiLevelForMemberDefinition(dexClassAndMethod.getDefinition(), minApiLevel);
+        },
+        lookupLambdaTarget -> {
+          // The implementation method will be assigned an api level when visited.
+        });
+  }
+
   private void setApiLevelForMemberDefinition(
       DexEncodedMember<?, ?> member, AndroidApiLevel apiLevel) {
     // To not have mutable update information for all members that all has min api level we
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
index dc87519..0610c55 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.graph.analysis;
 
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.LookupTarget;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -30,6 +31,12 @@
   /** Called when a method's code has been processed by the registry. */
   public void processTracedCode(ProgramMethod method, DefaultEnqueuerUseRegistry registry) {}
 
+  public void notifyMarkMethodAsTargeted(ProgramMethod method) {}
+
+  public void notifyMarkFieldAsReachable(ProgramField field) {}
+
+  public void notifyMarkVirtualDispatchTargetAsLive(LookupTarget target) {}
+
   /**
    * Called when the Enqueuer reaches a fixpoint. This may happen multiple times, since each
    * analysis may enqueue items into the worklist upon the fixpoint using {@param worklist}.
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index 7483522..a772278 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.horizontalclassmerging;
 
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
 import static com.google.common.base.Predicates.not;
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
@@ -32,6 +33,7 @@
 import com.android.tools.r8.ir.analysis.value.NumberFromIntervalValue;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.SetUtils;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
@@ -43,6 +45,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Function;
 
 /**
  * The class merger is responsible for moving methods from the sources in {@link ClassMerger#group}
@@ -127,6 +130,7 @@
         newMethodReference.withName("$r8$clinit$synthetic", dexItemFactory);
     lensBuilder.recordNewMethodSignature(syntheticMethodReference, newMethodReference, true);
 
+    AndroidApiLevel apiReferenceLevel = classInitializerMerger.getApiReferenceLevel(appView);
     DexEncodedMethod definition =
         new DexEncodedMethod(
             newMethodReference,
@@ -136,7 +140,9 @@
             ParameterAnnotationsList.empty(),
             classInitializerMerger.getCode(syntheticMethodReference),
             DexEncodedMethod.D8_R8_SYNTHESIZED,
-            classInitializerMerger.getCfVersion());
+            classInitializerMerger.getCfVersion(),
+            getApiLevelIfEnabledForNewMember(appView, ignored -> apiReferenceLevel),
+            getApiLevelIfEnabledForNewMember(appView, ignored -> apiReferenceLevel));
     classMethodsBuilder.addDirectMethod(definition);
 
     // In case we didn't synthesize CF code, we register the class initializer for conversion to dex
@@ -223,7 +229,8 @@
             DexAnnotationSet.empty(),
             null,
             deprecated,
-            d8R8Synthesized);
+            d8R8Synthesized,
+            getApiLevelIfEnabledForNewMember(appView, Function.identity()));
 
     // For the $r8$classId synthesized fields, we try to over-approximate the set of values it may
     // have. For example, for a merge group of size 4, we may compute the set {0, 2, 3}, if the
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
index e17c574..adc89fc 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.horizontalclassmerging;
 
 import static com.android.tools.r8.dex.Constants.TEMPORARY_INSTANCE_INITIALIZER_PREFIX;
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
 
 import com.android.tools.r8.cf.CfVersion;
 import com.android.tools.r8.dex.Constants;
@@ -360,6 +361,7 @@
           instanceInitializer.getReference(), newMethodReference, extraParameters);
     }
 
+    DexEncodedMethod representativeMethod = representative.getDefinition();
     DexEncodedMethod newInstanceInitializer =
         new DexEncodedMethod(
             newMethodReference,
@@ -369,7 +371,11 @@
             ParameterAnnotationsList.empty(),
             getNewCode(newMethodReference, syntheticMethodReference, needsClassId, extraNulls),
             true,
-            getNewClassFileVersion());
+            getNewClassFileVersion(),
+            getApiLevelIfEnabledForNewMember(
+                appView, representativeMethod::getApiReferenceLevelForDefinition),
+            getApiLevelIfEnabledForNewMember(
+                appView, representativeMethod::getApiReferenceLevelForCode));
     classMethodsBuilder.addDirectMethod(newInstanceInitializer);
 
     if (mode.isFinal()) {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index 394c884..d5f2b8b 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.horizontalclassmerging;
 
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
+
 import com.android.tools.r8.cf.CfVersion;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -267,7 +269,7 @@
             originalMethodReference.proto,
             originalMethodReference.getHolderType(),
             classMethodsBuilder::isFresh);
-
+    DexEncodedMethod representativeMethod = representative.getDefinition();
     DexMethod newMethodReference = getNewMethodReference();
     AbstractSynthesizedCode synthesizedCode =
         new VirtualMethodEntryPointSynthesizedCode(
@@ -286,7 +288,11 @@
             ParameterAnnotationsList.empty(),
             synthesizedCode,
             true,
-            classFileVersion);
+            classFileVersion,
+            getApiLevelIfEnabledForNewMember(
+                appView, representativeMethod::getApiReferenceLevelForDefinition),
+            getApiLevelIfEnabledForNewMember(
+                appView, representativeMethod::getApiReferenceLevelForCode));
     if (!representative.getDefinition().isLibraryMethodOverride().isUnknown()) {
       newMethod.setLibraryMethodOverride(representative.getDefinition().isLibraryMethodOverride());
     }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
index ade97ad..cff4480 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.horizontalclassmerging.code;
 
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabled;
 import static java.lang.Integer.max;
 
 import com.android.tools.r8.cf.CfVersion;
@@ -34,6 +35,7 @@
 import com.android.tools.r8.ir.code.Return;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.CfVersionUtils;
 import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.ListUtils;
@@ -98,6 +100,18 @@
     return null;
   }
 
+  public AndroidApiLevel getApiReferenceLevel(AppView<?> appView) {
+    assert !classInitializers.isEmpty();
+    return ListUtils.fold(
+        classInitializers,
+        appView.options().apiModelingOptions().enableApiCallerIdentification
+            ? appView.options().minApiLevel
+            : AndroidApiLevel.UNKNOWN,
+        (accApiLevel, method) ->
+            accApiLevel.max(
+                getApiLevelIfEnabled(appView, method.getDefinition()::getApiReferenceLevel)));
+  }
+
   public static class Builder {
 
     private final ImmutableList.Builder<ProgramMethod> classInitializers = ImmutableList.builder();
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java
index 97d8d21..3b7e1e0 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java
@@ -13,13 +13,13 @@
 public class NoDifferentApiReferenceLevel extends MultiClassSameReferencePolicy<AndroidApiLevel> {
 
   private final AndroidApiReferenceLevelCache apiReferenceLevelCache;
-  private final AndroidApiLevel minApi;
+  private final AppView<?> appView;
   // TODO(b/188388130): Remove when stabilized.
   private final boolean enableApiCallerIdentification;
 
   public NoDifferentApiReferenceLevel(AppView<?> appView) {
     apiReferenceLevelCache = AndroidApiReferenceLevelCache.create(appView);
-    minApi = appView.options().minApiLevel;
+    this.appView = appView;
     enableApiCallerIdentification =
         appView.options().apiModelingOptions().enableApiCallerIdentification;
   }
@@ -37,6 +37,6 @@
   @Override
   public AndroidApiLevel getMergeKey(DexProgramClass clazz) {
     assert enableApiCallerIdentification;
-    return clazz.getApiReferenceLevel(minApi, apiReferenceLevelCache::lookupMax);
+    return clazz.getApiReferenceLevel(appView, apiReferenceLevelCache::lookupMax);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
index 9508da1..136d452 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
@@ -13,8 +13,6 @@
 import com.android.tools.r8.ir.desugar.CfClassDesugaringEventConsumer.D8CfClassDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer.D8CfInstructionDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer.D8CfPostProcessingDesugaringEventConsumer;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
@@ -112,13 +110,6 @@
 
       classes = deferred;
     }
-
-    D8CfPostProcessingDesugaringEventConsumer eventConsumer =
-        CfPostProcessingDesugaringEventConsumer.createForD8(methodProcessor, appView);
-    methodProcessor.newWave();
-    converter.postProcessDesugaring(eventConsumer);
-    methodProcessor.awaitMethodProcessing();
-    eventConsumer.finalizeDesugaring();
   }
 
   abstract void convertClass(
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 0b3c524..3144113 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -51,11 +51,13 @@
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer.D8CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringCollection;
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer.D8CfPostProcessingDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer;
 import com.android.tools.r8.ir.desugar.ProgramAdditions;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter.Mode;
 import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceApplicationRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor;
 import com.android.tools.r8.ir.desugar.lambda.LambdaDeserializationMethodRemover;
@@ -105,7 +107,6 @@
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.ExceptionUtils;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.InternalOptions.DesugarState;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.ThreadUtils;
@@ -226,10 +227,7 @@
       assert options.desugarState.isOn();
       this.instructionDesugaring = CfInstructionDesugaringCollection.create(appView);
       this.classDesugaring = instructionDesugaring.createClassDesugaringCollection();
-      this.interfaceMethodRewriter =
-          options.desugaredLibraryConfiguration.getEmulateLibraryInterface().isEmpty()
-              ? null
-              : new InterfaceMethodRewriter(appView, this);
+      this.interfaceMethodRewriter = null;
       this.desugaredLibraryAPIConverter =
           new DesugaredLibraryAPIConverter(appView, Mode.GENERATE_CALLBACKS_AND_WRAPPERS);
       this.covariantReturnTypeAnnotationTransformer = null;
@@ -259,7 +257,7 @@
             : CfInstructionDesugaringCollection.create(appView);
     this.classDesugaring = instructionDesugaring.createClassDesugaringCollection();
     this.interfaceMethodRewriter =
-        options.isInterfaceMethodDesugaringEnabled()
+        options.isInterfaceMethodDesugaringEnabled() && appView.enableWholeProgramOptimizations()
             ? new InterfaceMethodRewriter(appView, this)
             : null;
     this.covariantReturnTypeAnnotationTransformer =
@@ -367,11 +365,6 @@
         D8NestBasedAccessDesugaring::clearNestAttributes);
   }
 
-  void postProcessDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) {
-    CfPostProcessingDesugaringCollection.create(appView, instructionDesugaring.getRetargetingInfo())
-        .postProcessingDesugaring(eventConsumer);
-  }
-
   private void staticizeClasses(
       OptimizationFeedback feedback, ExecutorService executorService, GraphLens applied)
       throws ExecutionException {
@@ -394,11 +387,11 @@
     }
   }
 
-  private void runInterfaceDesugaringProcessors(
+  private void runInterfaceDesugaringProcessorsForR8(
       Flavor includeAllResources, ExecutorService executorService) throws ExecutionException {
     assert !appView.getSyntheticItems().hasPendingSyntheticClasses();
     if (interfaceMethodRewriter != null) {
-      interfaceMethodRewriter.runInterfaceDesugaringProcessors(
+      interfaceMethodRewriter.runInterfaceDesugaringProcessorsForR8(
           this, includeAllResources, executorService);
     }
   }
@@ -415,25 +408,24 @@
     workaroundAbstractMethodOnNonAbstractClassVerificationBug(
         executor, OptimizationFeedbackIgnore.getInstance());
     DexApplication application = appView.appInfo().app();
+    D8MethodProcessor methodProcessor = new D8MethodProcessor(this, executor);
+
     timing.begin("IR conversion");
 
-    convertClasses(executor);
+    convertClasses(methodProcessor, executor);
 
     reportNestDesugarDependencies();
     clearNestAttributes();
 
-    if (appView.getSyntheticItems().hasPendingSyntheticClasses()) {
-      appView.setAppInfo(
-          new AppInfo(
-              appView.appInfo().getSyntheticItems().commit(application),
-              appView.appInfo().getMainDexInfo()));
-      application = appView.appInfo().app();
-    }
+    application = commitPendingSyntheticItems(appView, application);
+
+    postProcessingDesugaringForD8(methodProcessor, executor);
+
+    application = commitPendingSyntheticItems(appView, application);
 
     // Build a new application with jumbo string info,
     Builder<?> builder = application.builder().setHighestSortingString(highestSortingString);
 
-    runInterfaceDesugaringProcessors(ExcludeDexResources, executor);
     if (appView.options().isDesugaredLibraryCompilation()) {
       new EmulatedInterfaceApplicationRewriter(appView).rewriteApplication(builder);
     }
@@ -449,8 +441,34 @@
             appView.appInfo().getMainDexInfo()));
   }
 
-  private void convertClasses(ExecutorService executorService) throws ExecutionException {
-    D8MethodProcessor methodProcessor = new D8MethodProcessor(this, executorService);
+  private DexApplication commitPendingSyntheticItems(
+      AppView<AppInfo> appView, DexApplication application) {
+    if (appView.getSyntheticItems().hasPendingSyntheticClasses()) {
+      appView.setAppInfo(
+          new AppInfo(
+              appView.appInfo().getSyntheticItems().commit(application),
+              appView.appInfo().getMainDexInfo()));
+      application = appView.appInfo().app();
+    }
+    return application;
+  }
+
+  private void postProcessingDesugaringForD8(
+      D8MethodProcessor methodProcessor, ExecutorService executorService)
+      throws ExecutionException {
+    D8CfPostProcessingDesugaringEventConsumer eventConsumer =
+        CfPostProcessingDesugaringEventConsumer.createForD8(methodProcessor, appView);
+    methodProcessor.newWave();
+    InterfaceMethodProcessorFacade interfaceDesugaring =
+        instructionDesugaring.getInterfaceMethodPostProcessingDesugaring(ExcludeDexResources);
+    CfPostProcessingDesugaringCollection.create(
+            appView, interfaceDesugaring, instructionDesugaring.getRetargetingInfo())
+        .postProcessingDesugaring(eventConsumer, executorService);
+    eventConsumer.finalizeDesugaring();
+  }
+
+  private void convertClasses(D8MethodProcessor methodProcessor, ExecutorService executorService)
+      throws ExecutionException {
     ClassConverterResult classConverterResult =
         ClassConverter.create(appView, this, methodProcessor).convertClasses(executorService);
 
@@ -797,7 +815,7 @@
 
     printPhase("Interface method desugaring");
     finalizeInterfaceMethodRewritingThroughIR(executorService);
-    runInterfaceDesugaringProcessors(IncludeAllResources, executorService);
+    runInterfaceDesugaringProcessorsForR8(IncludeAllResources, executorService);
     feedback.updateVisibleOptimizationInfo();
 
     printPhase("Desugared library API Conversion finalization");
@@ -1445,12 +1463,6 @@
     deadCodeRemover.run(code, timing);
     assert code.isConsistentSSA();
 
-    if (options.desugarState == DesugarState.ON && options.enableTryWithResourcesDesugaring()) {
-      timing.begin("Rewrite Throwable suppresed methods");
-      codeRewriter.rewriteThrowableAddAndGetSuppressed(code);
-      timing.end();
-    }
-
     previous = printMethod(code, "IR after lambda desugaring (SSA)", previous);
 
     assert code.verifyTypes(appView);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
index 6efa25b..8512734 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
@@ -8,6 +8,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor;
 import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
 import com.android.tools.r8.utils.ThrowingConsumer;
 
@@ -58,5 +60,8 @@
   public abstract <T extends Throwable> void withD8NestBasedAccessDesugaring(
       ThrowingConsumer<D8NestBasedAccessDesugaring, T> consumer) throws T;
 
+  public abstract InterfaceMethodProcessorFacade getInterfaceMethodPostProcessingDesugaring(
+      Flavor flavor);
+
   public abstract RetargetingInfo getRetargetingInfo();
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaring.java
index 2a2de5f..38a0413 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaring.java
@@ -3,7 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.desugar;
 
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
 public interface CfPostProcessingDesugaring {
 
-  void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer);
+  void postProcessingDesugaring(
+      CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
+      throws ExecutionException;
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
index f659ad8..986c6ea 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
@@ -6,15 +6,21 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterPostProcessor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
-import java.util.Collections;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
 
 public abstract class CfPostProcessingDesugaringCollection {
 
   public static CfPostProcessingDesugaringCollection create(
-      AppView<?> appView, RetargetingInfo retargetingInfo) {
+      AppView<?> appView,
+      InterfaceMethodProcessorFacade interfaceMethodProcessorFacade,
+      RetargetingInfo retargetingInfo) {
     if (appView.options().desugarState.isOn()) {
-      return NonEmptyCfPostProcessingDesugaringCollection.create(appView, retargetingInfo);
+      return NonEmptyCfPostProcessingDesugaringCollection.create(
+          appView, interfaceMethodProcessorFacade, retargetingInfo);
     }
     return empty();
   }
@@ -24,7 +30,8 @@
   }
 
   public abstract void postProcessingDesugaring(
-      CfPostProcessingDesugaringEventConsumer eventConsumer);
+      CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
+      throws ExecutionException;
 
   public static class NonEmptyCfPostProcessingDesugaringCollection
       extends CfPostProcessingDesugaringCollection {
@@ -37,19 +44,29 @@
     }
 
     public static CfPostProcessingDesugaringCollection create(
-        AppView<?> appView, RetargetingInfo retargetingInfo) {
-      if (appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) {
+        AppView<?> appView,
+        InterfaceMethodProcessorFacade interfaceMethodProcessorFacade,
+        RetargetingInfo retargetingInfo) {
+      if (appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()
+          && interfaceMethodProcessorFacade == null) {
         return empty();
       }
-      return new NonEmptyCfPostProcessingDesugaringCollection(
-          Collections.singletonList(
-              new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo)));
+      ArrayList<CfPostProcessingDesugaring> desugarings = new ArrayList<>();
+      if (!appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) {
+        desugarings.add(new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo));
+      }
+      if (interfaceMethodProcessorFacade != null) {
+        desugarings.add(interfaceMethodProcessorFacade);
+      }
+      return new NonEmptyCfPostProcessingDesugaringCollection(desugarings);
     }
 
     @Override
-    public void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) {
+    public void postProcessingDesugaring(
+        CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
+        throws ExecutionException {
       for (CfPostProcessingDesugaring desugaring : desugarings) {
-        desugaring.postProcessingDesugaring(eventConsumer);
+        desugaring.postProcessingDesugaring(eventConsumer, executorService);
       }
     }
   }
@@ -67,7 +84,9 @@
     }
 
     @Override
-    public void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) {
+    public void postProcessingDesugaring(
+        CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
+        throws ExecutionException {
       // Intentionally empty.
     }
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
index dc67ee9..5734cab 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
@@ -11,7 +11,10 @@
 import com.android.tools.r8.ir.conversion.D8MethodProcessor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterInstructionEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer;
+import com.android.tools.r8.ir.desugar.itf.InterfaceProcessingDesugaringEventConsumer;
 import com.android.tools.r8.shaking.Enqueuer.SyntheticAdditions;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import java.util.concurrent.ExecutionException;
 
 /**
  * Specialized Event consumer for desugaring finalization. During finalization, it is not possible
@@ -19,7 +22,8 @@
  * explicit calls must be done here.
  */
 public abstract class CfPostProcessingDesugaringEventConsumer
-    implements DesugaredLibraryRetargeterPostProcessingEventConsumer {
+    implements DesugaredLibraryRetargeterPostProcessingEventConsumer,
+        InterfaceProcessingDesugaringEventConsumer {
   protected DesugaredLibraryAPIConverter desugaredLibraryAPIConverter;
 
   protected CfPostProcessingDesugaringEventConsumer(AppView<?> appView) {
@@ -36,13 +40,14 @@
     return new R8PostProcessingDesugaringEventConsumer(appView, additions);
   }
 
-  public void finalizeDesugaring() {
-    desugaredLibraryAPIConverter.generateTrackingWarnings();
-  }
+  public abstract void finalizeDesugaring() throws ExecutionException;
 
   public static class D8CfPostProcessingDesugaringEventConsumer
       extends CfPostProcessingDesugaringEventConsumer {
     private final D8MethodProcessor methodProcessor;
+    // Methods cannot be processed directly because we cannot add method to classes while
+    // concurrently processing other methods.
+    private final ProgramMethodSet methodsToReprocess = ProgramMethodSet.createConcurrent();
 
     private D8CfPostProcessingDesugaringEventConsumer(
         D8MethodProcessor methodProcessor, AppView<?> appView) {
@@ -52,7 +57,7 @@
 
     @Override
     public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
-      methodProcessor.scheduleDesugaredMethodsForProcessing(clazz.programMethods());
+      methodsToReprocess.addAll(clazz.programMethods());
     }
 
     @Override
@@ -67,9 +72,25 @@
 
     @Override
     public void acceptForwardingMethod(ProgramMethod method) {
-      methodProcessor.scheduleDesugaredMethodForProcessing(method);
-      // TODO(b/189912077): Uncomment when API conversion is performed cf to cf in D8.
-      // desugaredLibraryAPIConverter.generateCallbackIfRequired(method);
+      methodsToReprocess.add(method);
+    }
+
+    @Override
+    public void acceptCompanionClassClinit(ProgramMethod method) {
+      methodsToReprocess.add(method);
+    }
+
+    @Override
+    public void acceptEmulatedInterfaceMethod(ProgramMethod method) {
+      methodsToReprocess.add(method);
+    }
+
+    @Override
+    public void finalizeDesugaring() throws ExecutionException {
+      assert methodProcessor.verifyNoPendingMethodProcessing();
+      methodProcessor.newWave();
+      methodProcessor.scheduleDesugaredMethodsForProcessing(methodsToReprocess);
+      methodProcessor.awaitMethodProcessing();
     }
   }
 
@@ -84,6 +105,11 @@
     }
 
     @Override
+    public void finalizeDesugaring() throws ExecutionException {
+      desugaredLibraryAPIConverter.generateTrackingWarnings();
+    }
+
+    @Override
     public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
       additions.addLiveMethods(clazz.programMethods());
     }
@@ -106,5 +132,15 @@
         additions.addLiveMethod(callback);
       }
     }
+
+    @Override
+    public void acceptCompanionClassClinit(ProgramMethod method) {
+      assert false : "TODO(b/183998768): Support Interface processing in R8";
+    }
+
+    @Override
+    public void acceptEmulatedInterfaceMethod(ProgramMethod method) {
+      assert false : "TODO(b/183998768): Support Interface processing in R8";
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java
index 61c9617..7991ac3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java
@@ -8,6 +8,8 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.CfClassDesugaringCollection.EmptyCfClassDesugaringCollection;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor;
 import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
 import com.android.tools.r8.utils.ThrowingConsumer;
 
@@ -63,6 +65,11 @@
   }
 
   @Override
+  public InterfaceMethodProcessorFacade getInterfaceMethodPostProcessingDesugaring(Flavor flavor) {
+    return null;
+  }
+
+  @Override
   public RetargetingInfo getRetargetingInfo() {
     return null;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index 3b5a40b..2d53448 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.ir.desugar;
 
 import static com.android.tools.r8.ir.desugar.lambda.ForcefullyMovedLambdaMethodConsumer.emptyForcefullyMovedLambdaMethodConsumer;
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
 import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
 
 import com.android.tools.r8.dex.Constants;
@@ -43,6 +44,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.function.Consumer;
+import java.util.function.Function;
 
 /**
  * Represents lambda class generated for a lambda descriptor in context of lambda instantiation
@@ -241,7 +243,8 @@
               DexAnnotationSet.empty(),
               null,
               deprecated,
-              d8R8Synthesized));
+              d8R8Synthesized,
+              getApiLevelIfEnabledForNewMember(appView, Function.identity())));
     }
     builder.setInstanceFields(fields);
   }
@@ -266,7 +269,8 @@
                   DexAnnotationSet.empty(),
                   DexValueNull.NULL,
                   deprecated,
-                  d8R8Synthesized)));
+                  d8R8Synthesized,
+                  getApiLevelIfEnabledForNewMember(appView, Function.identity()))));
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index 8ddd45c..a7f1a33 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -17,13 +17,15 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
 import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialToSelfDesugaring;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor;
 import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
 import com.android.tools.r8.ir.desugar.nest.NestBasedAccessDesugaring;
 import com.android.tools.r8.ir.desugar.records.RecordRewriter;
 import com.android.tools.r8.ir.desugar.stringconcat.StringConcatInstructionDesugaring;
-import com.android.tools.r8.ir.desugar.twr.TwrCloseResourceInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.twr.TwrInstructionDesugaring;
 import com.android.tools.r8.utils.IntBox;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.StringDiagnostic;
@@ -42,6 +44,7 @@
   private final NestBasedAccessDesugaring nestBasedAccessDesugaring;
   private final RecordRewriter recordRewriter;
   private final DesugaredLibraryRetargeter desugaredLibraryRetargeter;
+  private final InterfaceMethodRewriter interfaceMethodRewriter;
 
   NonEmptyCfInstructionDesugaringCollection(AppView<?> appView) {
     this.appView = appView;
@@ -49,6 +52,7 @@
       this.nestBasedAccessDesugaring = null;
       this.recordRewriter = null;
       this.desugaredLibraryRetargeter = null;
+      this.interfaceMethodRewriter = null;
       return;
     }
     this.nestBasedAccessDesugaring = NestBasedAccessDesugaring.create(appView);
@@ -65,14 +69,17 @@
     }
     // Place TWR before Interface desugaring to eliminate potential $closeResource interface calls.
     if (appView.options().enableTryWithResourcesDesugaring()) {
-      desugarings.add(new TwrCloseResourceInstructionDesugaring(appView));
+      desugarings.add(new TwrInstructionDesugaring(appView));
     }
     // TODO(b/183998768): Enable interface method rewriter cf to cf also in R8.
-    if (appView.options().isInterfaceMethodDesugaringEnabled()
-        && !appView.enableWholeProgramOptimizations()) {
-      desugarings.add(
-          new InterfaceMethodRewriter(
-              appView, backportedMethodRewriter, desugaredLibraryRetargeter));
+    interfaceMethodRewriter =
+        appView.options().isInterfaceMethodDesugaringEnabled()
+                && !appView.enableWholeProgramOptimizations()
+            ? new InterfaceMethodRewriter(
+                appView, backportedMethodRewriter, desugaredLibraryRetargeter)
+            : null;
+    if (interfaceMethodRewriter != null) {
+      desugarings.add(interfaceMethodRewriter);
     }
     desugarings.add(new LambdaInstructionDesugaring(appView));
     desugarings.add(new InvokeSpecialToSelfDesugaring(appView));
@@ -288,7 +295,7 @@
                   || (appliedDesugaring instanceof InterfaceMethodRewriter
                       && (desugaring instanceof InvokeToPrivateRewriter
                           || desugaring instanceof D8NestBasedAccessDesugaring))
-                  || (appliedDesugaring instanceof TwrCloseResourceInstructionDesugaring
+                  || (appliedDesugaring instanceof TwrInstructionDesugaring
                       && desugaring instanceof InterfaceMethodRewriter)
               : "Desugaring of "
                   + instruction
@@ -312,6 +319,13 @@
   }
 
   @Override
+  public InterfaceMethodProcessorFacade getInterfaceMethodPostProcessingDesugaring(Flavor flavor) {
+    return interfaceMethodRewriter != null
+        ? interfaceMethodRewriter.getPostProcessingDesugaring(flavor)
+        : null;
+  }
+
+  @Override
   public RetargetingInfo getRetargetingInfo() {
     if (desugaredLibraryRetargeter != null) {
       return desugaredLibraryRetargeter.getRetargetingInfo();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java
index 0b0039e..dac3079 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java
@@ -23,6 +23,8 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
 
 // The rewrite of virtual calls requires to go through emulate dispatch. This class is responsible
 // for inserting interfaces on library boundaries and forwarding methods in the program, and to
@@ -41,7 +43,9 @@
   }
 
   @Override
-  public void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) {
+  public void postProcessingDesugaring(
+      CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
+      throws ExecutionException {
     if (appView.options().isDesugaredLibraryCompilation()) {
       ensureEmulatedDispatchMethodsSynthesized(eventConsumer);
     } else {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index d86d22c..14e5fea 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -380,7 +380,8 @@
   }
 
   @Override
-  public void process(DexProgramClass clazz, ProgramMethodSet synthesizedMethods) {
+  public void process(
+      DexProgramClass clazz, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     if (!clazz.isInterface()) {
       visitClassInfo(clazz, new ReportingContext(clazz, clazz));
     }
@@ -389,11 +390,11 @@
   // We introduce forwarding methods only once all desugaring has been performed to avoid
   // confusing the look-up with inserted forwarding methods.
   @Override
-  public final void finalizeProcessing(ProgramMethodSet synthesizedMethods) {
+  public final void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     newSyntheticMethods.forEach(
         (clazz, newForwardingMethods) -> {
           clazz.addVirtualMethods(newForwardingMethods.toDefinitionSet());
-          newForwardingMethods.forEach(synthesizedMethods::add);
+          newForwardingMethods.forEach(eventConsumer::acceptForwardingMethod);
         });
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
index 46bd871..1c29a09 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
@@ -19,7 +19,6 @@
 import com.android.tools.r8.synthesis.SyntheticNaming;
 import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.StringDiagnostic;
-import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
@@ -89,7 +88,7 @@
   }
 
   DexProgramClass ensureEmulateInterfaceLibrary(
-      DexProgramClass emulatedInterface, ProgramMethodSet synthesizedMethods) {
+      DexProgramClass emulatedInterface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     assert rewriter.isEmulatedInterface(emulatedInterface.type);
     DexProgramClass emulateInterfaceClass =
         appView
@@ -107,7 +106,7 @@
                                     synthesizeEmulatedInterfaceMethod(
                                         method, emulatedInterface, methodBuilder))),
                 ignored -> {});
-    emulateInterfaceClass.forEachProgramMethod(synthesizedMethods::add);
+    emulateInterfaceClass.forEachProgramMethod(eventConsumer::acceptEmulatedInterfaceMethod);
     assert emulateInterfaceClass.getType()
         == InterfaceMethodRewriter.getEmulateLibraryInterfaceClassType(
             emulatedInterface.type, appView.dexItemFactory());
@@ -212,14 +211,15 @@
   }
 
   @Override
-  public void process(DexProgramClass emulatedInterface, ProgramMethodSet synthesizedMethods) {
+  public void process(
+      DexProgramClass emulatedInterface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     if (!appView.options().isDesugaredLibraryCompilation()
         || !rewriter.isEmulatedInterface(emulatedInterface.type)
         || appView.isAlreadyLibraryDesugared(emulatedInterface)) {
       return;
     }
     if (needsEmulateInterfaceLibrary(emulatedInterface)) {
-      ensureEmulateInterfaceLibrary(emulatedInterface, synthesizedMethods);
+      ensureEmulateInterfaceLibrary(emulatedInterface, eventConsumer);
     }
   }
 
@@ -228,7 +228,7 @@
   }
 
   @Override
-  public void finalizeProcessing(ProgramMethodSet synthesizedMethods) {
+  public void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     warnMissingEmulatedInterfaces();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java
index 7f3d047..4f4ba32 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.ir.desugar.itf;
 
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.utils.collections.ProgramMethodSet;
 
 public interface InterfaceDesugaringProcessor {
 
@@ -14,11 +13,11 @@
   // so this phase cannot modify the classes themselves (for example insertion/removal of methods).
   // The phase can insert new classes with new methods, such as emulated interface dispatch classes
   // or companion classes with their methods.
-  void process(DexProgramClass clazz, ProgramMethodSet synthesizedMethods);
+  void process(DexProgramClass clazz, InterfaceProcessingDesugaringEventConsumer eventConsumer);
 
   // The finalization phase is done at a join point, after all code desugaring have been performed.
   // All finalization phases of all desugaring processors are performed sequentially.
   // Complex computations should be avoided if possible here and be moved to the concurrent phase.
   // Classes may be mutated here (new methods can be inserted, etc.).
-  void finalizeProcessing(ProgramMethodSet synthesizedMethods);
+  void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer);
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java
index 731316f..71844b0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java
@@ -6,7 +6,10 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring;
+import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
@@ -16,21 +19,22 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 
-class InterfaceMethodProcessorFacade {
+public class InterfaceMethodProcessorFacade implements CfPostProcessingDesugaring {
 
   private final AppView<?> appView;
+  private final Flavor flavour;
+  private final List<InterfaceDesugaringProcessor> interfaceDesugaringProcessors;
 
-  InterfaceMethodProcessorFacade(AppView<?> appView) {
+  InterfaceMethodProcessorFacade(
+      AppView<?> appView, Flavor flavour, InterfaceMethodRewriter rewriter) {
     this.appView = appView;
+    this.flavour = flavour;
+    interfaceDesugaringProcessors = instantiateInterfaceDesugaringProcessors(appView, rewriter);
   }
 
-  /** Runs the interfaceProcessor, the class processor and the emulated interface processor. */
-  void runInterfaceDesugaringProcessors(
-      InterfaceMethodRewriter rewriter,
-      IRConverter converter,
-      Flavor flavour,
-      ExecutorService executorService)
-      throws ExecutionException {
+  private List<InterfaceDesugaringProcessor> instantiateInterfaceDesugaringProcessors(
+      AppView<?> appView, InterfaceMethodRewriter rewriter) {
+
     // During L8 compilation, emulated interfaces are processed to be renamed, to have
     // their interfaces fixed-up and to generate the emulated dispatch code.
     EmulatedInterfaceProcessor emulatedInterfaceProcessor =
@@ -46,17 +50,47 @@
     // classes if needed.
     InterfaceProcessor interfaceProcessor = new InterfaceProcessor(appView, rewriter);
 
-    // The interface processors must be ordered so that finalization of the processing is performed
-    // in that order. The emulatedInterfaceProcessor has to be last at this point to avoid renaming
-    // emulated interfaces before the other processing.
-    ImmutableList<InterfaceDesugaringProcessor> orderedInterfaceDesugaringProcessors =
-        ImmutableList.of(classProcessor, interfaceProcessor, emulatedInterfaceProcessor);
+    // The processors can be listed in any order.
+    return ImmutableList.of(classProcessor, interfaceProcessor, emulatedInterfaceProcessor);
+  }
+
+  /** Runs the interfaceProcessor, the class processor and the emulated interface processor. */
+  void runInterfaceDesugaringProcessorsForR8(IRConverter converter, ExecutorService executorService)
+      throws ExecutionException {
+
+    CollectingInterfaceDesugaringEventConsumer eventConsumer =
+        new CollectingInterfaceDesugaringEventConsumer();
+    processClassesConcurrently(eventConsumer, executorService);
+    converter.processMethodsConcurrently(
+        eventConsumer.getSortedSynthesizedMethods(), executorService);
+  }
+
+  // This temporary class avoids the duality between collecting with IR processing and
+  // having events with the Cf desugaring.
+  private static class CollectingInterfaceDesugaringEventConsumer
+      implements InterfaceProcessingDesugaringEventConsumer {
 
     SortedProgramMethodSet sortedSynthesizedMethods = SortedProgramMethodSet.createConcurrent();
-    processClassesConcurrently(
-        orderedInterfaceDesugaringProcessors, sortedSynthesizedMethods, flavour, executorService);
-    assert converter != null;
-    converter.processMethodsConcurrently(sortedSynthesizedMethods, executorService);
+
+    @Override
+    public void acceptForwardingMethod(ProgramMethod method) {
+      sortedSynthesizedMethods.add(method);
+    }
+
+    @Override
+    public void acceptCompanionClassClinit(ProgramMethod method) {
+      sortedSynthesizedMethods.add(method);
+    }
+
+    @Override
+    public void acceptEmulatedInterfaceMethod(ProgramMethod method) {
+
+      sortedSynthesizedMethods.add(method);
+    }
+
+    public SortedProgramMethodSet getSortedSynthesizedMethods() {
+      return sortedSynthesizedMethods;
+    }
   }
 
   private boolean shouldProcess(DexProgramClass clazz, Flavor flavour) {
@@ -67,22 +101,28 @@
   }
 
   private void processClassesConcurrently(
-      List<InterfaceDesugaringProcessor> processors,
-      SortedProgramMethodSet sortedSynthesizedMethods,
-      Flavor flavour,
-      ExecutorService executorService)
+      InterfaceProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
       throws ExecutionException {
     ThreadUtils.processItems(
         Iterables.filter(
             appView.appInfo().classes(), (DexProgramClass clazz) -> shouldProcess(clazz, flavour)),
         clazz -> {
-          for (InterfaceDesugaringProcessor processor : processors) {
-            processor.process(clazz, sortedSynthesizedMethods);
+          for (InterfaceDesugaringProcessor processor : interfaceDesugaringProcessors) {
+            processor.process(clazz, eventConsumer);
           }
         },
         executorService);
-    for (InterfaceDesugaringProcessor processor : processors) {
-      processor.finalizeProcessing(sortedSynthesizedMethods);
+    for (InterfaceDesugaringProcessor processor : interfaceDesugaringProcessors) {
+      processor.finalizeProcessing(eventConsumer);
     }
   }
+
+  @Override
+  public void postProcessingDesugaring(
+      CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
+      throws ExecutionException {
+    // TODO(b/183998768): Would be nice to use the ClassProcessing for the processing of classes,
+    //  and do here only the finalization.
+    processClassesConcurrently(eventConsumer, executorService);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index 6ab6f1f..3e93691 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -1376,11 +1376,15 @@
     this.synthesizedMethods.clear();
   }
 
-  public void runInterfaceDesugaringProcessors(
+  public void runInterfaceDesugaringProcessorsForR8(
       IRConverter converter, Flavor flavour, ExecutorService executorService)
       throws ExecutionException {
-    new InterfaceMethodProcessorFacade(appView)
-        .runInterfaceDesugaringProcessors(this, converter, flavour, executorService);
+    getPostProcessingDesugaring(flavour)
+        .runInterfaceDesugaringProcessorsForR8(converter, executorService);
+  }
+
+  public InterfaceMethodProcessorFacade getPostProcessingDesugaring(Flavor flavour) {
+    return new InterfaceMethodProcessorFacade(appView, flavour, this);
   }
 
   final boolean isDefaultMethod(DexEncodedMethod method) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java
new file mode 100644
index 0000000..2581364
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java
@@ -0,0 +1,16 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.itf;
+
+import com.android.tools.r8.graph.ProgramMethod;
+
+public interface InterfaceProcessingDesugaringEventConsumer {
+
+  void acceptForwardingMethod(ProgramMethod method);
+
+  void acceptCompanionClassClinit(ProgramMethod method);
+
+  void acceptEmulatedInterfaceMethod(ProgramMethod method);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index cb752ad..2dd65a9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -47,7 +47,6 @@
 import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
 import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
 import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
-import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -80,12 +79,13 @@
   }
 
   @Override
-  public void process(DexProgramClass iface, ProgramMethodSet synthesizedMethods) {
+  public void process(
+      DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     if (!iface.isInterface()) {
       return;
     }
     analyzeBridges(iface);
-    ensureCompanionClassMethods(iface, synthesizedMethods);
+    ensureCompanionClassMethods(iface, eventConsumer);
   }
 
   private void analyzeBridges(DexProgramClass iface) {
@@ -99,8 +99,8 @@
   }
 
   private void ensureCompanionClassMethods(
-      DexProgramClass iface, ProgramMethodSet synthesizedMethods) {
-    ensureCompanionClassInitializesInterface(iface, synthesizedMethods);
+      DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
+    ensureCompanionClassInitializesInterface(iface, eventConsumer);
     // TODO(b/183998768): Once fixed, the methods should be added for processing.
     // D8 and R8 don't need to optimize the methods since they are just moved from interfaces and
     // don't need to be re-processed.
@@ -134,7 +134,7 @@
   }
 
   private void ensureCompanionClassInitializesInterface(
-      DexProgramClass iface, ProgramMethodSet synthesizedMethods) {
+      DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     if (!hasStaticMethodThatTriggersNonTrivialClassInitializer(iface)) {
       return;
     }
@@ -146,7 +146,7 @@
             appView.dexItemFactory().createProto(appView.dexItemFactory().voidType),
             appView,
             methodBuilder -> createCompanionClassInitializer(iface, clinitField, methodBuilder));
-    synthesizedMethods.add(clinit);
+    eventConsumer.acceptCompanionClassClinit(clinit);
   }
 
   private DexEncodedField ensureStaticClinitFieldToTriggerInterfaceInitialization(
@@ -441,7 +441,7 @@
   }
 
   @Override
-  public void finalizeProcessing(ProgramMethodSet synthesizedMethods) {
+  public void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     InterfaceProcessorNestedGraphLens graphLens = postProcessInterfaces();
     if (appView.enableWholeProgramOptimizations() && graphLens != null) {
       appView.setGraphLens(graphLens);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrCloseResourceInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrCloseResourceInstructionDesugaring.java
deleted file mode 100644
index 212259a..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrCloseResourceInstructionDesugaring.java
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.ir.desugar.twr;
-
-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.graph.AppView;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
-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.backports.BackportedMethods;
-import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
-import com.google.common.collect.ImmutableList;
-import java.util.Collection;
-import org.objectweb.asm.Opcodes;
-
-public class TwrCloseResourceInstructionDesugaring implements CfInstructionDesugaring {
-
-  private final AppView<?> appView;
-  private final DexItemFactory dexItemFactory;
-  private final DexProto twrCloseResourceProto;
-
-  public TwrCloseResourceInstructionDesugaring(AppView<?> appView) {
-    this.appView = appView;
-    this.dexItemFactory = appView.dexItemFactory();
-    this.twrCloseResourceProto =
-        dexItemFactory.createProto(
-            dexItemFactory.voidType, dexItemFactory.throwableType, dexItemFactory.objectType);
-  }
-
-  @Override
-  public Collection<CfInstruction> desugarInstruction(
-      CfInstruction instruction,
-      FreshLocalProvider freshLocalProvider,
-      LocalStackAllocator localStackAllocator,
-      CfInstructionDesugaringEventConsumer eventConsumer,
-      ProgramMethod context,
-      MethodProcessingContext methodProcessingContext,
-      DexItemFactory dexItemFactory) {
-    if (!instruction.isInvokeStatic()) {
-      return null;
-    }
-
-    CfInvoke invoke = instruction.asInvoke();
-    DexMethod invokedMethod = invoke.getMethod();
-    if (!isTwrCloseResourceMethod(invokedMethod)) {
-      return null;
-    }
-
-    // Synthesize a new method.
-    ProgramMethod closeMethod = createSyntheticCloseResourceMethod(methodProcessingContext);
-    eventConsumer.acceptTwrCloseResourceMethod(closeMethod, context);
-
-    // Rewrite the invoke to the new synthetic.
-    return ImmutableList.of(new CfInvoke(Opcodes.INVOKESTATIC, closeMethod.getReference(), false));
-  }
-
-  private ProgramMethod createSyntheticCloseResourceMethod(
-      MethodProcessingContext methodProcessingContext) {
-    return appView
-        .getSyntheticItems()
-        .createMethod(
-            SyntheticKind.TWR_CLOSE_RESOURCE,
-            methodProcessingContext.createUniqueContext(),
-            appView,
-            methodBuilder ->
-                methodBuilder
-                    .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
-                    .setProto(twrCloseResourceProto)
-                    .setCode(
-                        m ->
-                            BackportedMethods.CloseResourceMethod_closeResourceImpl(
-                                appView.options(), m)));
-  }
-
-  @Override
-  public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
-    return instruction.isInvokeStatic()
-        && isTwrCloseResourceMethod(instruction.asInvoke().getMethod());
-  }
-
-  private boolean isTwrCloseResourceMethod(DexMethod method) {
-    return method.name == dexItemFactory.twrCloseResourceMethodName
-        && method.proto == dexItemFactory.twrCloseResourceMethodProto;
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java
new file mode 100644
index 0000000..b63846d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java
@@ -0,0 +1,166 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.desugar.twr;
+
+import com.android.tools.r8.cf.code.CfConstNumber;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfNewArray;
+import com.android.tools.r8.cf.code.CfStackInstruction;
+import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
+import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+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.backports.BackportedMethods;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import org.jetbrains.annotations.NotNull;
+import org.objectweb.asm.Opcodes;
+
+public class TwrInstructionDesugaring implements CfInstructionDesugaring {
+
+  private final AppView<?> appView;
+  private final DexItemFactory dexItemFactory;
+  private final DexProto twrCloseResourceProto;
+  private final DexMethod addSuppressed;
+  private final DexMethod getSuppressed;
+
+  public TwrInstructionDesugaring(AppView<?> appView) {
+    this.appView = appView;
+    this.dexItemFactory = appView.dexItemFactory();
+    this.twrCloseResourceProto =
+        dexItemFactory.createProto(
+            dexItemFactory.voidType, dexItemFactory.throwableType, dexItemFactory.objectType);
+    this.addSuppressed = dexItemFactory.throwableMethods.addSuppressed;
+    this.getSuppressed = dexItemFactory.throwableMethods.getSuppressed;
+  }
+
+  @Override
+  public Collection<CfInstruction> desugarInstruction(
+      CfInstruction instruction,
+      FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
+      CfInstructionDesugaringEventConsumer eventConsumer,
+      ProgramMethod context,
+      MethodProcessingContext methodProcessingContext,
+      DexItemFactory dexItemFactory) {
+    if (!instruction.isInvoke()) {
+      return null;
+    }
+    if (isTwrCloseResourceInvoke(instruction)) {
+      return rewriteTwrCloseResourceInvoke(eventConsumer, context, methodProcessingContext);
+    }
+    if (isTwrSuppressedInvoke(instruction, addSuppressed)) {
+      return rewriteTwrAddSuppressedInvoke();
+    }
+    if (isTwrSuppressedInvoke(instruction, getSuppressed)) {
+      return rewriteTwrGetSuppressedInvoke();
+    }
+    return null;
+  }
+
+  private Collection<CfInstruction> rewriteTwrAddSuppressedInvoke() {
+    // Remove Throwable::addSuppressed(Throwable) call.
+    return ImmutableList.of(new CfStackInstruction(Opcode.Pop), new CfStackInstruction(Opcode.Pop));
+  }
+
+  private Collection<CfInstruction> rewriteTwrGetSuppressedInvoke() {
+    // Replace call to Throwable::getSuppressed() with new Throwable[0].
+    return ImmutableList.of(
+        new CfStackInstruction(Opcode.Pop),
+        new CfConstNumber(0, ValueType.INT),
+        new CfNewArray(dexItemFactory.createArrayType(1, dexItemFactory.throwableType)));
+  }
+
+  @NotNull
+  private ImmutableList<CfInstruction> rewriteTwrCloseResourceInvoke(
+      CfInstructionDesugaringEventConsumer eventConsumer,
+      ProgramMethod context,
+      MethodProcessingContext methodProcessingContext) {
+    // Synthesize a new method.
+    ProgramMethod closeMethod = createSyntheticCloseResourceMethod(methodProcessingContext);
+    eventConsumer.acceptTwrCloseResourceMethod(closeMethod, context);
+    // Rewrite the invoke to the new synthetic.
+    return ImmutableList.of(new CfInvoke(Opcodes.INVOKESTATIC, closeMethod.getReference(), false));
+  }
+
+  private ProgramMethod createSyntheticCloseResourceMethod(
+      MethodProcessingContext methodProcessingContext) {
+    return appView
+        .getSyntheticItems()
+        .createMethod(
+            SyntheticKind.TWR_CLOSE_RESOURCE,
+            methodProcessingContext.createUniqueContext(),
+            appView,
+            methodBuilder ->
+                methodBuilder
+                    .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
+                    .setProto(twrCloseResourceProto)
+                    .setCode(
+                        m ->
+                            BackportedMethods.CloseResourceMethod_closeResourceImpl(
+                                appView.options(), m)));
+  }
+
+  @Override
+  public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
+    if (!instruction.isInvoke()) {
+      return false;
+    }
+    return isTwrCloseResourceInvoke(instruction)
+        || isTwrSuppressedInvoke(instruction, addSuppressed)
+        || isTwrSuppressedInvoke(instruction, getSuppressed);
+  }
+
+  private boolean isTwrSuppressedInvoke(CfInstruction instruction, DexMethod suppressed) {
+    return instruction.isInvoke()
+        && matchesMethodOfThrowable(instruction.asInvoke().getMethod(), suppressed);
+  }
+
+  private boolean matchesMethodOfThrowable(DexMethod invoked, DexMethod expected) {
+    return invoked.name == expected.name
+        && invoked.proto == expected.proto
+        && isSubtypeOfThrowable(invoked.holder);
+  }
+
+  private boolean isSubtypeOfThrowable(DexType type) {
+    while (type != null && type != dexItemFactory.objectType) {
+      if (type == dexItemFactory.throwableType) {
+        return true;
+      }
+      DexClass dexClass = appView.definitionFor(type);
+      if (dexClass == null) {
+        throw new CompilationError(
+            "Class or interface "
+                + type.toSourceString()
+                + " required for desugaring of try-with-resources is not found.");
+      }
+      type = dexClass.superType;
+    }
+    return false;
+  }
+
+  private boolean isTwrCloseResourceInvoke(CfInstruction instruction) {
+    return instruction.isInvokeStatic()
+        && isTwrCloseResourceMethod(instruction.asInvoke().getMethod());
+  }
+
+  private boolean isTwrCloseResourceMethod(DexMethod method) {
+    return method.name == dexItemFactory.twrCloseResourceMethodName
+        && method.proto == dexItemFactory.twrCloseResourceMethodProto;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 2a1ec57..86fb8e9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -21,7 +21,6 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexItemFactory.ThrowableMethods;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
@@ -3651,75 +3650,6 @@
     }
   }
 
-  // Removes calls to Throwable.addSuppressed(Throwable) and rewrites
-  // Throwable.getSuppressed() into new Throwable[0].
-  //
-  // Note that addSuppressed() and getSuppressed() methods are final in
-  // Throwable, so these changes don't have to worry about overrides.
-  public void rewriteThrowableAddAndGetSuppressed(IRCode code) {
-    ThrowableMethods throwableMethods = dexItemFactory.throwableMethods;
-
-    for (BasicBlock block : code.blocks) {
-      InstructionListIterator iterator = block.listIterator(code);
-      while (iterator.hasNext()) {
-        Instruction current = iterator.next();
-        if (current.isInvokeMethod()) {
-          DexMethod invokedMethod = current.asInvokeMethod().getInvokedMethod();
-          if (matchesMethodOfThrowable(invokedMethod, throwableMethods.addSuppressed)) {
-            // Remove Throwable::addSuppressed(Throwable) call.
-            iterator.removeOrReplaceByDebugLocalRead();
-          } else if (matchesMethodOfThrowable(invokedMethod, throwableMethods.getSuppressed)) {
-            Value destValue = current.outValue();
-            if (destValue == null) {
-              // If the result of the call was not used we don't create
-              // an empty array and just remove the call.
-              iterator.removeOrReplaceByDebugLocalRead();
-              continue;
-            }
-
-            // Replace call to Throwable::getSuppressed() with new Throwable[0].
-
-            // First insert the constant value *before* the current instruction.
-            ConstNumber zero = code.createIntConstant(0);
-            zero.setPosition(current.getPosition());
-            assert iterator.hasPrevious();
-            iterator.previous();
-            iterator.add(zero);
-
-            // Then replace the invoke instruction with new-array instruction.
-            Instruction next = iterator.next();
-            assert current == next;
-            NewArrayEmpty newArray = new NewArrayEmpty(destValue, zero.outValue(),
-                dexItemFactory.createType(dexItemFactory.throwableArrayDescriptor));
-            iterator.replaceCurrentInstruction(newArray);
-          }
-        }
-      }
-    }
-    assert code.isConsistentSSA();
-  }
-
-  private boolean matchesMethodOfThrowable(DexMethod invoked, DexMethod expected) {
-    return invoked.name == expected.name
-        && invoked.proto == expected.proto
-        && isSubtypeOfThrowable(invoked.holder);
-  }
-
-  private boolean isSubtypeOfThrowable(DexType type) {
-    while (type != null && type != dexItemFactory.objectType) {
-      if (type == dexItemFactory.throwableType) {
-        return true;
-      }
-      DexClass dexClass = appView.definitionFor(type);
-      if (dexClass == null) {
-        throw new CompilationError("Class or interface " + type.toSourceString() +
-            " required for desugaring of try-with-resources is not found.");
-      }
-      type = dexClass.superType;
-    }
-    return false;
-  }
-
   private Value addConstString(IRCode code, InstructionListIterator iterator, String s) {
     TypeElement typeLattice = TypeElement.stringClassType(appView, definitelyNotNull());
     Value value = code.createValue(typeLattice);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index ececbe3..8c5f439 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -3,9 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize;
 
-import static com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo.isApiSafeForInlining;
 import static com.android.tools.r8.ir.optimize.inliner.InlinerUtils.addMonitorEnterValue;
 import static com.android.tools.r8.ir.optimize.inliner.InlinerUtils.collectAllMonitorEnterValues;
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.isApiSafeForInlining;
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.features.ClassToFeatureSplitMap;
@@ -130,11 +130,9 @@
     }
 
     // Do not inline if the inlinee is greater than the api caller level.
-    MethodOptimizationInfo callerOptimizationInfo = method.getDefinition().getOptimizationInfo();
     // TODO(b/188498051): We should not force inline lower api method calls.
     if (reason != Reason.FORCE
-        && isApiSafeForInlining(callerOptimizationInfo, targetOptimizationInfo, appView.options())
-            .isPossiblyFalse()) {
+        && isApiSafeForInlining(method, singleTarget, appView.options()).isPossiblyFalse()) {
       whyAreYouNotInliningReporter.reportInlineeHigherApiCall();
       return false;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index e653838..01d23b6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.ir.optimize.classinliner;
 
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.isApiSafeForInlining;
 
 import com.android.tools.r8.errors.InternalCompilerError;
 import com.android.tools.r8.errors.Unreachable;
@@ -879,7 +880,10 @@
     if (instanceInitializerInfo.receiverMayEscapeOutsideConstructorChain()) {
       return null;
     }
-
+    // Check the api level is allowed to be inlined.
+    if (isApiSafeForInlining(method, singleTarget, appView.options()).isPossiblyFalse()) {
+      return null;
+    }
     // Check that the entire constructor chain can be inlined into the current context.
     DexMethod parent = instanceInitializerInfo.getParent();
     while (parent != dexItemFactory.objectMembers.constructor) {
@@ -906,6 +910,10 @@
           NopWhyAreYouNotInliningReporter.getInstance())) {
         return null;
       }
+      // Check the api level is allowed to be inlined.
+      if (isApiSafeForInlining(method, encodedParent, appView.options()).isPossiblyFalse()) {
+        return null;
+      }
       parent =
           encodedParentMethod
               .getOptimizationInfo()
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
index 5cbab1f..7a95765 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.ir.optimize.enums;
 
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
+
 import com.android.tools.r8.cf.CfVersion;
 import com.android.tools.r8.cf.code.CfArrayStore;
 import com.android.tools.r8.cf.code.CfConstNumber;
@@ -46,6 +48,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Function;
 import org.objectweb.asm.Opcodes;
 
 public class SharedEnumUnboxingUtilityClass extends EnumUnboxingUtilityClass {
@@ -234,7 +237,8 @@
               DexAnnotationSet.empty(),
               DexEncodedField.NO_STATIC_VALUE,
               DexEncodedField.NOT_DEPRECATED,
-              DexEncodedField.D8_R8_SYNTHESIZED);
+              DexEncodedField.D8_R8_SYNTHESIZED,
+              getApiLevelIfEnabledForNewMember(appView, Function.identity()));
       fieldAccessInfoCollectionModifierBuilder
           .recordFieldReadInUnknownContext(valuesField.getReference())
           .recordFieldWriteInUnknownContext(valuesField.getReference());
@@ -253,7 +257,9 @@
           ParameterAnnotationsList.empty(),
           createClassInitializerCode(sharedUtilityClassType, valuesField),
           DexEncodedMethod.D8_R8_SYNTHESIZED,
-          CfVersion.V1_6);
+          CfVersion.V1_6,
+          getApiLevelIfEnabledForNewMember(appView, Function.identity()),
+          getApiLevelIfEnabledForNewMember(appView, Function.identity()));
     }
 
     private CfCode createClassInitializerCode(
@@ -298,7 +304,9 @@
               ParameterAnnotationsList.empty(),
               createValuesMethodCode(sharedUtilityClassType, valuesField),
               DexEncodedMethod.D8_R8_SYNTHESIZED,
-              CfVersion.V1_6);
+              CfVersion.V1_6,
+              getApiLevelIfEnabledForNewMember(appView, Function.identity()),
+              getApiLevelIfEnabledForNewMember(appView, Function.identity()));
       this.valuesMethod = valuesMethod;
       return valuesMethod;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
index aebd195..31ecb9b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
@@ -42,7 +42,6 @@
   static boolean UNKNOWN_RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS = false;
   static BitSet NO_NULL_PARAMETER_OR_THROW_FACTS = null;
   static BitSet NO_NULL_PARAMETER_ON_NORMAL_EXITS_FACTS = null;
-  static AndroidApiLevel UNKNOWN_API_REFERENCE_LEVEL = null;
 
   protected DefaultMethodOptimizationInfo() {}
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
index 30c8d7a..bb45fbc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
@@ -4,8 +4,6 @@
 
 package com.android.tools.r8.ir.optimize.info;
 
-import static com.android.tools.r8.utils.OptionalBool.UNKNOWN;
-
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
@@ -19,7 +17,6 @@
 import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.OptionalBool;
 import java.util.BitSet;
 import java.util.Set;
 
@@ -108,20 +105,6 @@
 
   public abstract AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi);
 
-  public static OptionalBool isApiSafeForInlining(
-      MethodOptimizationInfo caller, MethodOptimizationInfo inlinee, InternalOptions options) {
-    if (!options.apiModelingOptions().enableApiCallerIdentification) {
-      return OptionalBool.TRUE;
-    }
-    if (!caller.hasApiReferenceLevelForCode() || !inlinee.hasApiReferenceLevelForCode()) {
-      return UNKNOWN;
-    }
-    return OptionalBool.of(
-        caller
-            .getApiReferenceLevelForCode(options.minApiLevel)
-            .isGreaterThanOrEqualTo(inlinee.getApiReferenceLevelForCode(options.minApiLevel)));
-  }
-
   @Override
   public boolean isMethodOptimizationInfo() {
     return true;
diff --git a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
index ef44b4b..2bbd2b3 100644
--- a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
+++ b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
@@ -28,6 +28,8 @@
   public static final String NAME = "kotlin";
   public static final String PACKAGE_PREFIX = "L" + NAME + "/";
 
+  public final DexString kotlinJvmTypePrefix;
+
   public static final class ClassClassifiers {
 
     public static final String arrayBinaryName = NAME + "/Array";
@@ -41,6 +43,7 @@
     this.intrinsics = new Intrinsics();
     this.metadata = new Metadata();
     this.assertions = new _Assertions();
+    kotlinJvmTypePrefix = factory.createString("Lkotlin/jvm/");
   }
 
   public final class Functional {
@@ -67,10 +70,6 @@
     private Functional() {
     }
 
-    public final DexString kotlinStyleLambdaInstanceName = factory.createString("INSTANCE");
-
-    public final DexType functionBase =
-        factory.createType(PACKAGE_PREFIX + "jvm/internal/FunctionBase;");
     public final DexType lambdaType = factory.createType(PACKAGE_PREFIX + "jvm/internal/Lambda;");
 
     public final DexMethod lambdaInitializerMethod = factory.createMethod(
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
index 883be66..373a5d2 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
@@ -29,10 +29,10 @@
       ImmutableMap.of();
 
   abstract boolean rewrite(
-      Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens);
+      Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens);
 
   private static KotlinAnnotationArgumentInfo createArgument(
-      KmAnnotationArgument<?> arg, DexItemFactory factory) {
+      KmAnnotationArgument arg, DexItemFactory factory) {
     if (arg instanceof KClassValue) {
       return KotlinAnnotationClassValueInfo.create((KClassValue) arg, factory);
     } else if (arg instanceof EnumValue) {
@@ -47,7 +47,7 @@
   }
 
   static Map<String, KotlinAnnotationArgumentInfo> create(
-      Map<String, KmAnnotationArgument<?>> arguments, DexItemFactory factory) {
+      Map<String, KmAnnotationArgument> arguments, DexItemFactory factory) {
     if (arguments.isEmpty()) {
       return EMPTY_ARGUMENTS;
     }
@@ -59,14 +59,17 @@
   private static class KotlinAnnotationClassValueInfo extends KotlinAnnotationArgumentInfo {
 
     private final KotlinTypeReference value;
+    private final int arrayDimensionCount;
 
-    private KotlinAnnotationClassValueInfo(KotlinTypeReference value) {
+    private KotlinAnnotationClassValueInfo(KotlinTypeReference value, int arrayDimensionCount) {
       this.value = value;
+      this.arrayDimensionCount = arrayDimensionCount;
     }
 
     private static KotlinAnnotationClassValueInfo create(KClassValue arg, DexItemFactory factory) {
       return new KotlinAnnotationClassValueInfo(
-          KotlinTypeReference.fromBinaryName(arg.getValue(), factory));
+          KotlinTypeReference.fromBinaryName(arg.getClassName(), factory),
+          arg.getArrayDimensionCount());
     }
 
     @Override
@@ -76,9 +79,9 @@
 
     @Override
     boolean rewrite(
-        Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
+        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
       return value.toRenamedBinaryNameOrDefault(
-          rewrittenValue -> consumer.accept(new KClassValue(rewrittenValue)),
+          rewrittenValue -> consumer.accept(new KClassValue(rewrittenValue, arrayDimensionCount)),
           appView,
           namingLens,
           ClassClassifiers.anyName);
@@ -108,7 +111,7 @@
 
     @Override
     boolean rewrite(
-        Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
+        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
       return enumClassName.toRenamedBinaryNameOrDefault(
           rewrittenEnumClassName ->
               consumer.accept(new EnumValue(rewrittenEnumClassName, enumEntryName)),
@@ -129,7 +132,7 @@
     private static KotlinAnnotationAnnotationValueInfo create(
         AnnotationValue arg, DexItemFactory factory) {
       return new KotlinAnnotationAnnotationValueInfo(
-          KotlinAnnotationInfo.create(arg.getValue(), factory));
+          KotlinAnnotationInfo.create(arg.getAnnotation(), factory));
     }
 
     @Override
@@ -139,7 +142,7 @@
 
     @Override
     boolean rewrite(
-        Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
+        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
       return value.rewrite(
           rewrittenAnnotation -> {
             if (rewrittenAnnotation != null) {
@@ -163,11 +166,11 @@
     }
 
     private static KotlinAnnotationArrayValueInfo create(ArrayValue arg, DexItemFactory factory) {
-      if (arg.getValue().isEmpty()) {
+      if (arg.getElements().isEmpty()) {
         return EMPTY;
       }
       ImmutableList.Builder<KotlinAnnotationArgumentInfo> builder = ImmutableList.builder();
-      for (KmAnnotationArgument<?> argument : arg.getValue()) {
+      for (KmAnnotationArgument argument : arg.getElements()) {
         builder.add(createArgument(argument, factory));
       }
       return new KotlinAnnotationArrayValueInfo(builder.build());
@@ -182,8 +185,8 @@
 
     @Override
     boolean rewrite(
-        Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
-      List<KmAnnotationArgument<?>> rewrittenArguments = new ArrayList<>();
+        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
+      List<KmAnnotationArgument> rewrittenArguments = new ArrayList<>();
       boolean rewritten = false;
       for (KotlinAnnotationArgumentInfo kotlinAnnotationArgumentInfo : value) {
         rewritten |=
@@ -203,13 +206,13 @@
 
   private static class KotlinAnnotationPrimitiveArgumentInfo extends KotlinAnnotationArgumentInfo {
 
-    private final KmAnnotationArgument<?> argument;
+    private final KmAnnotationArgument argument;
 
-    private KotlinAnnotationPrimitiveArgumentInfo(KmAnnotationArgument<?> argument) {
+    private KotlinAnnotationPrimitiveArgumentInfo(KmAnnotationArgument argument) {
       this.argument = argument;
     }
 
-    private static KotlinAnnotationPrimitiveArgumentInfo create(KmAnnotationArgument<?> argument) {
+    private static KotlinAnnotationPrimitiveArgumentInfo create(KmAnnotationArgument argument) {
       return new KotlinAnnotationPrimitiveArgumentInfo(argument);
     }
 
@@ -220,7 +223,7 @@
 
     @Override
     boolean rewrite(
-        Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
+        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
       consumer.accept(argument);
       return false;
     }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
index fd036d8..cbdd76e 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
@@ -63,7 +63,7 @@
                 return;
               }
               String classifier = DescriptorUtils.descriptorToKotlinClassifier(renamedDescriptor);
-              Map<String, KmAnnotationArgument<?>> rewrittenArguments = new LinkedHashMap<>();
+              Map<String, KmAnnotationArgument> rewrittenArguments = new LinkedHashMap<>();
               arguments.forEach(
                   (key, arg) ->
                       rewritten.or(
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
index 08236e2..aa3731f 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
@@ -52,6 +52,11 @@
   private final String packageName;
   private final KotlinLocalDelegatedPropertyInfo localDelegatedProperties;
   private final int[] metadataVersion;
+  private final String inlineClassUnderlyingPropertyName;
+  private final KotlinTypeInfo inlineClassUnderlyingType;
+
+  // List of tracked assignments of kotlin metadata.
+  private final KotlinMetadataMembersTracker originalMembersWithKotlinInfo;
 
   private KotlinClassInfo(
       int flags,
@@ -69,7 +74,10 @@
       KotlinTypeReference anonymousObjectOrigin,
       String packageName,
       KotlinLocalDelegatedPropertyInfo localDelegatedProperties,
-      int[] metadataVersion) {
+      int[] metadataVersion,
+      String inlineClassUnderlyingPropertyName,
+      KotlinTypeInfo inlineClassUnderlyingType,
+      KotlinMetadataMembersTracker originalMembersWithKotlinInfo) {
     this.flags = flags;
     this.name = name;
     this.nameCanBeSynthesizedFromClassOrAnonymousObjectOrigin =
@@ -87,6 +95,9 @@
     this.packageName = packageName;
     this.localDelegatedProperties = localDelegatedProperties;
     this.metadataVersion = metadataVersion;
+    this.inlineClassUnderlyingPropertyName = inlineClassUnderlyingPropertyName;
+    this.inlineClassUnderlyingType = inlineClassUnderlyingType;
+    this.originalMembersWithKotlinInfo = originalMembersWithKotlinInfo;
   }
 
   public static KotlinClassInfo create(
@@ -112,6 +123,8 @@
     }
     ImmutableList.Builder<KotlinConstructorInfo> notBackedConstructors = ImmutableList.builder();
     int constructorIndex = 0;
+    KotlinMetadataMembersTracker originalMembersWithKotlinInfo =
+        new KotlinMetadataMembersTracker(appView);
     for (KmConstructor kmConstructor : kmClass.getConstructors()) {
       boolean readConstructorSignature =
           extensionInformation.hasJvmMethodSignatureExtensionForConstructor(constructorIndex++);
@@ -122,6 +135,7 @@
         DexEncodedMethod method = methodMap.get(signature.asString());
         if (method != null) {
           method.setKotlinMemberInfo(constructorInfo);
+          originalMembersWithKotlinInfo.add(method.getReference());
           continue;
         }
       }
@@ -130,7 +144,14 @@
     }
     KotlinDeclarationContainerInfo container =
         KotlinDeclarationContainerInfo.create(
-            kmClass, methodMap, fieldMap, factory, reporter, keepByteCode, extensionInformation);
+            kmClass,
+            methodMap,
+            fieldMap,
+            factory,
+            reporter,
+            keepByteCode,
+            extensionInformation,
+            originalMembersWithKotlinInfo);
     setCompanionObject(kmClass, hostClass, reporter);
     KotlinTypeReference anonymousObjectOrigin = getAnonymousObjectOrigin(kmClass, factory);
     boolean nameCanBeDeducedFromClassOrOrigin =
@@ -156,7 +177,10 @@
         packageName,
         KotlinLocalDelegatedPropertyInfo.create(
             JvmExtensionsKt.getLocalDelegatedProperties(kmClass), factory, reporter),
-        metadataVersion);
+        metadataVersion,
+        kmClass.getInlineClassUnderlyingPropertyName(),
+        KotlinTypeInfo.create(kmClass.getInlineClassUnderlyingType(), factory, reporter),
+        originalMembersWithKotlinInfo);
   }
 
   private static KotlinTypeReference getAnonymousObjectOrigin(
@@ -269,10 +293,12 @@
       rewritten |= constructorInfo.rewrite(kmClass, null, appView, namingLens);
     }
     // Find all constructors.
+    KotlinMetadataMembersTracker rewrittenReferences = new KotlinMetadataMembersTracker(appView);
     for (DexEncodedMethod method : clazz.methods()) {
       if (method.getKotlinInfo().isConstructor()) {
         KotlinConstructorInfo constructorInfo = method.getKotlinInfo().asConstructor();
         rewritten |= constructorInfo.rewrite(kmClass, method, appView, namingLens);
+        rewrittenReferences.add(method.getReference());
       }
     }
     // Rewrite functions, type-aliases and type-parameters.
@@ -283,7 +309,8 @@
             kmClass::visitTypeAlias,
             clazz,
             appView,
-            namingLens);
+            namingLens,
+            rewrittenReferences);
     // Rewrite type parameters.
     for (KotlinTypeParameterInfo typeParameter : typeParameters) {
       rewritten |= typeParameter.rewrite(kmClass::visitTypeParameter, appView, namingLens);
@@ -334,6 +361,12 @@
     // TODO(b/154347404): Understand enum entries.
     kmClass.getEnumEntries().addAll(enumEntries);
     rewritten |= versionRequirements.rewrite(kmClass::visitVersionRequirement);
+    if (inlineClassUnderlyingPropertyName != null && inlineClassUnderlyingType != null) {
+      kmClass.setInlineClassUnderlyingPropertyName(inlineClassUnderlyingPropertyName);
+      rewritten |=
+          inlineClassUnderlyingType.rewrite(
+              kmClass::visitInlineClassUnderlyingType, appView, namingLens);
+    }
     JvmClassExtensionVisitor extensionVisitor =
         (JvmClassExtensionVisitor) kmClass.visitExtensions(JvmClassExtensionVisitor.TYPE);
     extensionVisitor.visitModuleName(moduleName);
@@ -355,7 +388,9 @@
     extensionVisitor.visitEnd();
     KotlinClassMetadata.Class.Writer writer = new KotlinClassMetadata.Class.Writer();
     kmClass.accept(writer);
-    return Pair.create(writer.write().getHeader(), rewritten);
+    return Pair.create(
+        writer.write().getHeader(),
+        rewritten || !originalMembersWithKotlinInfo.isEqual(rewrittenReferences, appView));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
index 1b928d9..d166380 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
@@ -56,7 +56,8 @@
       DexItemFactory factory,
       Reporter reporter,
       Consumer<DexEncodedMethod> keepByteCode,
-      KotlinJvmSignatureExtensionInformation extensionInformation) {
+      KotlinJvmSignatureExtensionInformation extensionInformation,
+      KotlinMetadataMembersTracker originalAssignmentTracker) {
     ImmutableList.Builder<KotlinFunctionInfo> notBackedFunctions = ImmutableList.builder();
     int functionCounter = 0;
     for (KmFunction kmFunction : container.getFunctions()) {
@@ -88,6 +89,7 @@
       }
       keepIfInline(kmFunction.getFlags(), method, keepByteCode);
       method.setKotlinMemberInfo(kotlinFunctionInfo);
+      originalAssignmentTracker.add(method.getReference());
     }
 
     ImmutableList.Builder<KotlinPropertyInfo> notBackedProperties = ImmutableList.builder();
@@ -102,6 +104,7 @@
         if (field != null) {
           hasBacking = true;
           field.setKotlinMemberInfo(kotlinPropertyInfo);
+          originalAssignmentTracker.add(field.getReference());
         }
       }
       if (propertyProcessor.getterSignature() != null) {
@@ -111,6 +114,7 @@
           hasBacking = true;
           keepIfAccessorInline(kmProperty.getGetterFlags(), method, keepByteCode);
           method.setKotlinMemberInfo(kotlinPropertyInfo);
+          originalAssignmentTracker.add(method.getReference());
         }
       }
       if (propertyProcessor.setterSignature() != null) {
@@ -120,6 +124,7 @@
           hasBacking = true;
           keepIfAccessorInline(kmProperty.getGetterFlags(), method, keepByteCode);
           method.setKotlinMemberInfo(kotlinPropertyInfo);
+          originalAssignmentTracker.add(method.getReference());
         }
       }
       if (!hasBacking) {
@@ -161,7 +166,8 @@
       KmVisitorProviders.KmTypeAliasVisitorProvider typeAliasProvider,
       DexClass clazz,
       AppView<?> appView,
-      NamingLens namingLens) {
+      NamingLens namingLens,
+      KotlinMetadataMembersTracker rewrittenMembersWithKotlinInfo) {
     // Type aliases only have a representation here, so we can generate them directly.
     boolean rewritten = false;
     for (KotlinTypeAliasInfo typeAlias : typeAliases) {
@@ -175,6 +181,7 @@
             .computeIfAbsent(
                 field.getKotlinInfo().asProperty(), ignored -> new KotlinPropertyGroup())
             .setBackingField(field);
+        rewrittenMembersWithKotlinInfo.add(field.getReference());
       }
     }
     for (DexEncodedMethod method : clazz.methods()) {
@@ -184,12 +191,14 @@
                 .getKotlinInfo()
                 .asFunction()
                 .rewrite(functionProvider, method, appView, namingLens);
+        rewrittenMembersWithKotlinInfo.add(method.getReference());
         continue;
       }
       KotlinPropertyInfo kotlinPropertyInfo = method.getKotlinInfo().asProperty();
       if (kotlinPropertyInfo == null) {
         continue;
       }
+      rewrittenMembersWithKotlinInfo.add(method.getReference());
       KotlinPropertyGroup kotlinPropertyGroup =
           properties.computeIfAbsent(kotlinPropertyInfo, ignored -> new KotlinPropertyGroup());
       if (method.getReference().proto.returnType == appView.dexItemFactory().voidType) {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java
new file mode 100644
index 0000000..88691a9
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java
@@ -0,0 +1,65 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.kotlin;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMember;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.IterableUtils;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
+import java.util.Set;
+
+public class KotlinMetadataMembersTracker {
+
+  private int count;
+  // Only used for asserting equality during local testing.
+  private final Set<DexMember<?, ?>> references;
+
+  public KotlinMetadataMembersTracker(AppView<?> appView) {
+    references = appView.options().testing.enableTestAssertions ? Sets.newIdentityHashSet() : null;
+  }
+
+  public void add(DexMember<?, ?> reference) {
+    count += 1;
+    if (references != null) {
+      references.add(reference);
+    }
+  }
+
+  public boolean isEqual(KotlinMetadataMembersTracker tracker, AppView<?> appView) {
+    if (count != tracker.count) {
+      return false;
+    }
+    if (references != null) {
+      assert tracker.references != null;
+      assert references.size() == tracker.references.size();
+      SetView<DexMember<?, ?>> diffComparedToRewritten =
+          Sets.difference(references, tracker.references);
+      if (!diffComparedToRewritten.isEmpty()) {
+        SetView<DexMember<?, ?>> diffComparedToOriginal =
+            Sets.difference(tracker.references, references);
+        // Known kotlin types may not exist directly in the way they are annotated in the metadata.
+        // As an example kotlin.Function2 exists in the metadata but the concrete type is
+        // kotlin.jvm.functions.Function2. As a result we may not rewrite metadata but the
+        // underlying types are changed.
+        diffComparedToRewritten.forEach(
+            diff -> {
+              DexReference rewrittenReference = appView.graphLens().lookupReference(diff);
+              assert diffComparedToOriginal.contains(rewrittenReference);
+              assert IterableUtils.findOrDefault(
+                      diff.getReferencedTypes(), type -> isKotlinJvmType(appView, type), null)
+                  != null;
+            });
+      }
+    }
+    return true;
+  }
+
+  private boolean isKotlinJvmType(AppView<?> appView, DexType type) {
+    return type.descriptor.startsWith(appView.dexItemFactory().kotlin.kotlinJvmTypePrefix);
+  }
+}
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 a094a88..0ff0070 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -160,7 +160,8 @@
     try {
       Pair<KotlinClassHeader, Boolean> kotlinClassHeader = kotlinInfo.rewrite(clazz, appView, lens);
       // TODO(b/185756596): Remove when special handling is no longer needed.
-      if (!kotlinClassHeader.getSecond() && !appView.enableWholeProgramOptimizations()) {
+      if (!kotlinClassHeader.getSecond()
+          && appView.options().testing.keepMetadataInR8IfNotRewritten) {
         // No rewrite occurred and the data is the same as before.
         assert appView.checkForTesting(
             () ->
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
index fbfb3bb..ee9ea2c 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
@@ -325,6 +325,22 @@
                 appendKmType(nextIndent, sb, kmType);
               });
         });
+    if (kmClass.getInlineClassUnderlyingPropertyName() != null) {
+      appendKeyValue(
+          indent,
+          "inlineClassUnderlyingPropertyName",
+          sb,
+          kmClass.getInlineClassUnderlyingPropertyName());
+    }
+    if (kmClass.getInlineClassUnderlyingType() != null) {
+      appendKeyValue(
+          indent,
+          "inlineClassUnderlyingType",
+          sb,
+          nextIndent -> {
+            appendKmType(nextIndent, sb, kmClass.getInlineClassUnderlyingType());
+          });
+    }
     String companionObject = kmClass.getCompanionObject();
     appendKeyValue(
         indent, "enumEntries", sb, "[" + StringUtils.join(",", kmClass.getEnumEntries()) + "]");
@@ -769,7 +785,7 @@
               "arguments",
               sb,
               nextIndent -> {
-                Map<String, KmAnnotationArgument<?>> arguments = kmAnnotation.getArguments();
+                Map<String, KmAnnotationArgument> arguments = kmAnnotation.getArguments();
                 appendKmList(
                     nextIndent,
                     "{ key: String, value: KmAnnotationArgument<?> }",
@@ -795,9 +811,9 @@
   }
 
   private static void appendKmArgument(
-      String indent, StringBuilder sb, KmAnnotationArgument<?> annotationArgument) {
+      String indent, StringBuilder sb, KmAnnotationArgument annotationArgument) {
     if (annotationArgument instanceof KmAnnotationArgument.ArrayValue) {
-      List<KmAnnotationArgument<?>> value = ((ArrayValue) annotationArgument).getValue();
+      List<KmAnnotationArgument> value = ((ArrayValue) annotationArgument).getElements();
       appendKmList(
           indent,
           "ArrayValue",
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
index d28e7c3..fa483ae 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
@@ -27,14 +27,17 @@
   private final String moduleName;
   private final KotlinDeclarationContainerInfo containerInfo;
   private final KotlinLocalDelegatedPropertyInfo localDelegatedProperties;
+  private final KotlinMetadataMembersTracker originalMembersWithKotlinInfo;
 
   private KotlinPackageInfo(
       String moduleName,
       KotlinDeclarationContainerInfo containerInfo,
-      KotlinLocalDelegatedPropertyInfo localDelegatedProperties) {
+      KotlinLocalDelegatedPropertyInfo localDelegatedProperties,
+      KotlinMetadataMembersTracker originalMembersWithKotlinInfo) {
     this.moduleName = moduleName;
     this.containerInfo = containerInfo;
     this.localDelegatedProperties = localDelegatedProperties;
+    this.originalMembersWithKotlinInfo = originalMembersWithKotlinInfo;
   }
 
   public static KotlinPackageInfo create(
@@ -51,6 +54,8 @@
     for (DexEncodedMethod method : clazz.methods()) {
       methodMap.put(toJvmMethodSignature(method.getReference()).asString(), method);
     }
+    KotlinMetadataMembersTracker originalMembersWithKotlinInfo =
+        new KotlinMetadataMembersTracker(appView);
     return new KotlinPackageInfo(
         JvmExtensionsKt.getModuleName(kmPackage),
         KotlinDeclarationContainerInfo.create(
@@ -60,14 +65,17 @@
             appView.dexItemFactory(),
             appView.reporter(),
             keepByteCode,
-            extensionInformation),
+            extensionInformation,
+            originalMembersWithKotlinInfo),
         KotlinLocalDelegatedPropertyInfo.create(
             JvmExtensionsKt.getLocalDelegatedProperties(kmPackage),
             appView.dexItemFactory(),
-            appView.reporter()));
+            appView.reporter()),
+        originalMembersWithKotlinInfo);
   }
 
   boolean rewrite(KmPackage kmPackage, DexClass clazz, AppView<?> appView, NamingLens namingLens) {
+    KotlinMetadataMembersTracker rewrittenReferences = new KotlinMetadataMembersTracker(appView);
     boolean rewritten =
         containerInfo.rewrite(
             kmPackage::visitFunction,
@@ -75,7 +83,8 @@
             kmPackage::visitTypeAlias,
             clazz,
             appView,
-            namingLens);
+            namingLens,
+            rewrittenReferences);
     JvmPackageExtensionVisitor extensionVisitor =
         (JvmPackageExtensionVisitor) kmPackage.visitExtensions(JvmPackageExtensionVisitor.TYPE);
     rewritten |=
@@ -83,7 +92,7 @@
             extensionVisitor::visitLocalDelegatedProperty, appView, namingLens);
     extensionVisitor.visitModuleName(moduleName);
     extensionVisitor.visitEnd();
-    return rewritten;
+    return rewritten || !originalMembersWithKotlinInfo.isEqual(rewrittenReferences, appView);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
index b719c89..bc285b7 100644
--- a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
+++ b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
@@ -42,7 +42,9 @@
       throws ExecutionException {
     // Rewrite signature annotations for applications that are minified or if we have liveness
     // information, since we could have pruned types.
-    if (namingLens.isIdentityLens() && !appView.appInfo().hasLiveness()) {
+    if (namingLens.isIdentityLens()
+        && !appView.appInfo().hasLiveness()
+        && !appView.options().parseSignatureAttribute()) {
       return;
     }
     // Classes may not be the same as appInfo().classes() if applymapping is used on classpath
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
index e8d52aa..3d76d73 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.shaking;
 
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
@@ -21,6 +22,7 @@
 import com.android.tools.r8.utils.Visibility;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
+import java.util.function.Function;
 
 public class ClassInitFieldSynthesizer {
 
@@ -82,7 +84,6 @@
                   | Constants.ACC_PUBLIC
                   | Constants.ACC_STATIC);
       boolean deprecated = false;
-      boolean d8R8Synthesized = true;
       encodedClinitField =
           new DexEncodedField(
               appView.dexItemFactory().createField(clazz.type, clinitField.type, clinitField.name),
@@ -91,7 +92,8 @@
               DexAnnotationSet.empty(),
               null,
               deprecated,
-              d8R8Synthesized);
+              DexEncodedField.D8_R8_SYNTHESIZED,
+              getApiLevelIfEnabledForNewMember(appView, Function.identity()));
       clazz.appendStaticField(encodedClinitField);
     }
     lensBuilder.map(type, encodedClinitField.getReference());
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 822a7dc..645d5b9 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -116,6 +116,7 @@
 import com.android.tools.r8.shaking.EnqueuerEvent.ClassEnqueuerEvent;
 import com.android.tools.r8.shaking.EnqueuerEvent.InstantiatedClassEnqueuerEvent;
 import com.android.tools.r8.shaking.EnqueuerEvent.LiveClassEnqueuerEvent;
+import com.android.tools.r8.shaking.EnqueuerEvent.UnconditionalKeepInfoEvent;
 import com.android.tools.r8.shaking.EnqueuerWorklist.EnqueuerAction;
 import com.android.tools.r8.shaking.GraphReporter.KeepReasonWitness;
 import com.android.tools.r8.shaking.KeepInfoCollection.MutableKeepInfoCollection;
@@ -387,18 +388,6 @@
   private final MutableKeepInfoCollection keepInfo = new MutableKeepInfoCollection();
 
   /**
-   * The minimum keep info for classes, fields, and methods. The minimum keep info for a program
-   * item should be applied to the {@link KeepInfo} of that item when the item becomes live.
-   */
-  private final Map<DexProgramClass, KeepClassInfo.Joiner> minimumKeepClassInfo =
-      new IdentityHashMap<>();
-
-  private final ProgramFieldMap<KeepFieldInfo.Joiner> minimumKeepFieldInfo =
-      ProgramFieldMap.create();
-  private final ProgramMethodMap<KeepMethodInfo.Joiner> minimumKeepMethodInfo =
-      ProgramMethodMap.create();
-
-  /**
    * Conditional minimum keep info for classes, fields, and methods, which should only be applied if
    * the outermost {@link EnqueuerEvent} is triggered during tracing (e.g., class X becomes live).
    */
@@ -2290,9 +2279,9 @@
     }
   }
 
-  private void shouldNotBeMinified(DexReference reference) {
+  private void shouldNotBeMinified(ProgramDefinition definition) {
     if (options.isMinificationEnabled()) {
-      rootSet.shouldNotBeMinified(reference);
+      rootSet.shouldNotBeMinified(definition);
     }
   }
 
@@ -2300,17 +2289,17 @@
     KeepReasonWitness keepReasonWitness = graphReporter.registerClass(clazz, keepReason);
     markClassAsInstantiatedWithCompatRule(clazz.asProgramClass(), () -> keepReasonWitness);
     keepInfo.keepClass(clazz);
-    shouldNotBeMinified(clazz.getReference());
+    shouldNotBeMinified(clazz);
     clazz.forEachProgramField(
         field -> {
           keepInfo.keepField(field);
-          shouldNotBeMinified(field.getReference());
+          shouldNotBeMinified(field);
           markFieldAsKept(field, keepReasonWitness);
         });
     clazz.forEachProgramMethod(
         method -> {
           keepInfo.keepMethod(method);
-          shouldNotBeMinified(method.getReference());
+          shouldNotBeMinified(method);
           markMethodAsKept(method, keepReasonWitness);
         });
   }
@@ -2763,6 +2752,8 @@
     }
 
     traceFieldDefinition(field);
+
+    analyses.forEach(analysis -> analysis.notifyMarkFieldAsReachable(field));
   }
 
   private void traceFieldDefinition(ProgramField field) {
@@ -2836,7 +2827,7 @@
   }
 
   public boolean isPreconditionForMinimumKeepInfoSatisfied(EnqueuerEvent preconditionEvent) {
-    if (preconditionEvent == null) {
+    if (preconditionEvent == null || preconditionEvent.isUnconditionalKeepInfoEvent()) {
       return true;
     }
     if (preconditionEvent.isClassEvent()) {
@@ -2979,12 +2970,10 @@
 
   private void markVirtualDispatchTargetAsLive(
       LookupTarget target, Function<ProgramMethod, KeepReasonWitness> reason) {
-    if (target.isMethodTarget()) {
-      markVirtualDispatchTargetAsLive(target.asMethodTarget(), reason);
-    } else {
-      assert target.isLambdaTarget();
-      markVirtualDispatchTargetAsLive(target.asLambdaTarget(), reason);
-    }
+    target.accept(
+        method -> markVirtualDispatchTargetAsLive(method, reason),
+        lambda -> markVirtualDispatchTargetAsLive(lambda, reason));
+    analyses.forEach(analysis -> analysis.notifyMarkVirtualDispatchTargetAsLive(target));
   }
 
   private void markVirtualDispatchTargetAsLive(
@@ -3039,7 +3028,7 @@
       // marking for not renaming it is in the root set.
       workList.enqueueMarkMethodKeptAction(valuesMethod, reason);
       keepInfo.joinMethod(valuesMethod, joiner -> joiner.pin().disallowMinification());
-      shouldNotBeMinified(valuesMethod.getReference());
+      shouldNotBeMinified(valuesMethod);
     }
   }
 
@@ -3187,9 +3176,13 @@
   }
 
   private void applyMinimumKeepInfo(DexProgramClass clazz) {
-    KeepClassInfo.Joiner minimumKeepInfoForClass = minimumKeepClassInfo.remove(clazz);
-    if (minimumKeepInfoForClass != null) {
-      keepInfo.joinClass(clazz, info -> info.merge(minimumKeepInfoForClass));
+    Map<DexProgramClass, KeepClassInfo.Joiner> minimumKeepClassInfo =
+        dependentMinimumKeepClassInfo.get(UnconditionalKeepInfoEvent.get());
+    if (minimumKeepClassInfo != null) {
+      KeepClassInfo.Joiner minimumKeepInfoForClass = minimumKeepClassInfo.remove(clazz);
+      if (minimumKeepInfoForClass != null) {
+        keepInfo.joinClass(clazz, info -> info.merge(minimumKeepInfoForClass));
+      }
     }
   }
 
@@ -3198,7 +3191,8 @@
     if (liveTypes.contains(clazz)) {
       keepInfo.joinClass(clazz, info -> info.merge(minimumKeepInfo));
     } else {
-      minimumKeepClassInfo
+      dependentMinimumKeepClassInfo
+          .computeIfAbsent(UnconditionalKeepInfoEvent.get(), ignoreKey(IdentityHashMap::new))
           .computeIfAbsent(clazz, ignoreKey(KeepClassInfo::newEmptyJoiner))
           .merge(minimumKeepInfo);
     }
@@ -3219,9 +3213,13 @@
   }
 
   private void applyMinimumKeepInfo(ProgramField field) {
-    KeepFieldInfo.Joiner minimumKeepInfoForField = minimumKeepFieldInfo.remove(field);
-    if (minimumKeepInfoForField != null) {
-      keepInfo.joinField(field, info -> info.merge(minimumKeepInfoForField));
+    ProgramFieldMap<KeepFieldInfo.Joiner> minimumKeepFieldInfo =
+        dependentMinimumKeepFieldInfo.get(UnconditionalKeepInfoEvent.get());
+    if (minimumKeepFieldInfo != null) {
+      KeepFieldInfo.Joiner minimumKeepInfoForField = minimumKeepFieldInfo.remove(field);
+      if (minimumKeepInfoForField != null) {
+        keepInfo.joinField(field, info -> info.merge(minimumKeepInfoForField));
+      }
     }
   }
 
@@ -3230,7 +3228,8 @@
     if (liveFields.contains(field)) {
       keepInfo.joinField(field, info -> info.merge(minimumKeepInfo));
     } else {
-      minimumKeepFieldInfo
+      dependentMinimumKeepFieldInfo
+          .computeIfAbsent(UnconditionalKeepInfoEvent.get(), ignoreKey(ProgramFieldMap::create))
           .computeIfAbsent(field, ignoreKey(KeepFieldInfo::newEmptyJoiner))
           .merge(minimumKeepInfo);
     }
@@ -3249,9 +3248,13 @@
   }
 
   private void applyMinimumKeepInfo(ProgramMethod method) {
-    KeepMethodInfo.Joiner minimumKeepInfoForMethod = minimumKeepMethodInfo.remove(method);
-    if (minimumKeepInfoForMethod != null) {
-      keepInfo.joinMethod(method, info -> info.merge(minimumKeepInfoForMethod));
+    ProgramMethodMap<KeepMethodInfo.Joiner> minimumKeepMethodInfo =
+        dependentMinimumKeepMethodInfo.get(UnconditionalKeepInfoEvent.get());
+    if (minimumKeepMethodInfo != null) {
+      KeepMethodInfo.Joiner minimumKeepInfoForMethod = minimumKeepMethodInfo.remove(method);
+      if (minimumKeepInfoForMethod != null) {
+        keepInfo.joinMethod(method, info -> info.merge(minimumKeepInfoForMethod));
+      }
     }
   }
 
@@ -3260,7 +3263,8 @@
     if (liveMethods.contains(method) || targetedMethods.contains(method)) {
       keepInfo.joinMethod(method, info -> info.merge(minimumKeepInfo));
     } else {
-      minimumKeepMethodInfo
+      dependentMinimumKeepMethodInfo
+          .computeIfAbsent(UnconditionalKeepInfoEvent.get(), ignoreKey(ProgramMethodMap::create))
           .computeIfAbsent(method, ignoreKey(KeepMethodInfo::newEmptyJoiner))
           .merge(minimumKeepInfo);
     }
@@ -3886,14 +3890,14 @@
     }
   }
 
-  private void postProcessingDesugaring() {
+  private void postProcessingDesugaring() throws ExecutionException {
     SyntheticAdditions syntheticAdditions =
         new SyntheticAdditions(appView.createProcessorContext());
 
     R8PostProcessingDesugaringEventConsumer eventConsumer =
         CfPostProcessingDesugaringEventConsumer.createForR8(appView, syntheticAdditions);
-    CfPostProcessingDesugaringCollection.create(appView, desugaring.getRetargetingInfo())
-        .postProcessingDesugaring(eventConsumer);
+    CfPostProcessingDesugaringCollection.create(appView, null, desugaring.getRetargetingInfo())
+        .postProcessingDesugaring(eventConsumer, executorService);
 
     if (syntheticAdditions.isEmpty()) {
       return;
@@ -4189,6 +4193,7 @@
         markMethodAsLiveWithCompatRule(method);
       }
     }
+    analyses.forEach(analysis -> analysis.notifyMarkMethodAsTargeted(method));
   }
 
   void traceMethodDefinitionExcludingCode(ProgramMethod method) {
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java
index 6f68a59..ba7ee40 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java
@@ -33,6 +33,10 @@
     return null;
   }
 
+  public boolean isUnconditionalKeepInfoEvent() {
+    return false;
+  }
+
   public abstract static class ClassEnqueuerEvent extends EnqueuerEvent {
 
     private final DexType clazz;
@@ -123,4 +127,20 @@
       return (getType().hashCode() << 1) | 1;
     }
   }
+
+  public static class UnconditionalKeepInfoEvent extends EnqueuerEvent {
+
+    private static final UnconditionalKeepInfoEvent INSTANCE = new UnconditionalKeepInfoEvent();
+
+    private UnconditionalKeepInfoEvent() {}
+
+    public static UnconditionalKeepInfoEvent get() {
+      return INSTANCE;
+    }
+
+    @Override
+    public boolean isUnconditionalKeepInfoEvent() {
+      return true;
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
index 8e5e7a3..57f27cf 100644
--- a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
@@ -42,15 +42,22 @@
       typeMap.put(aClass.type, aClass);
     }
     List<DexProgramClass> toKeep = new ArrayList<>();
+    boolean pruneNestMember = false;
     for (DexProgramClass aClass : app.classes()) {
       if (rewritePrefix.hasRewrittenType(aClass.type, null)
           || emulatedInterfaces.contains(aClass.type)
           || interfaceImplementsEmulatedInterface(aClass, typeMap)) {
         toKeep.add(aClass);
       } else {
+        pruneNestMember |= aClass.isInANest();
         pruned.add(aClass.type);
       }
     }
+    if (pruneNestMember) {
+      for (DexProgramClass keptClass : toKeep) {
+        TreePruner.rewriteNestAttributes(keptClass, type -> !pruned.contains(type), typeMap::get);
+      }
+    }
     typeMap.clear();
     // TODO(b/134732760): Would be nice to add pruned type to the appView removedClasses instead
     // of just doing nothing with it.
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 28094a1..03e9de3 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -36,6 +36,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMember;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -51,6 +52,7 @@
 import com.android.tools.r8.shaking.DelayedRootSetActionItem.InterfaceMethodSyntheticBridgeAction;
 import com.android.tools.r8.shaking.EnqueuerEvent.InstantiatedClassEnqueuerEvent;
 import com.android.tools.r8.shaking.EnqueuerEvent.LiveClassEnqueuerEvent;
+import com.android.tools.r8.shaking.EnqueuerEvent.UnconditionalKeepInfoEvent;
 import com.android.tools.r8.shaking.KeepInfo.Joiner;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.Consumer3;
@@ -96,37 +98,23 @@
 
 public class RootSetUtils {
 
-  static void modifyMinimumKeepInfo(
-      Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo,
-      DexDefinition definition,
-      Consumer<Joiner<?, ?, ?>> consumer) {
-    modifyMinimumKeepInfo(minimumKeepInfo, definition.getReference(), consumer);
-  }
-
-  static void modifyMinimumKeepInfo(
-      Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo,
-      DexReference reference,
-      Consumer<Joiner<?, ?, ?>> consumer) {
-    Joiner<?, ?, ?> joiner =
-        minimumKeepInfo.computeIfAbsent(
-            reference,
-            key ->
-                key.apply(
-                    clazz -> KeepClassInfo.newEmptyJoiner(),
-                    field -> KeepFieldInfo.newEmptyJoiner(),
-                    method -> KeepMethodInfo.newEmptyJoiner()));
-    consumer.accept(joiner);
-    assert !joiner.isBottom();
-  }
-
   static void modifyDependentMinimumKeepInfo(
       Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo,
       EnqueuerEvent event,
-      DexDefinition dependent,
+      ProgramDefinition dependent,
       Consumer<Joiner<?, ?, ?>> consumer) {
-    Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfoForDependants =
-        dependentMinimumKeepInfo.computeIfAbsent(event, ignoreKey(IdentityHashMap::new));
-    modifyMinimumKeepInfo(minimumKeepInfoForDependants, dependent, consumer);
+    Joiner<?, ?, ?> joiner =
+        dependentMinimumKeepInfo
+            .computeIfAbsent(event, ignoreKey(IdentityHashMap::new))
+            .computeIfAbsent(
+                dependent.getReference(),
+                key ->
+                    key.apply(
+                        clazz -> KeepClassInfo.newEmptyJoiner(),
+                        field -> KeepFieldInfo.newEmptyJoiner(),
+                        method -> KeepMethodInfo.newEmptyJoiner()));
+    consumer.accept(joiner);
+    assert !joiner.isBottom();
   }
 
   public static class RootSetBuilder {
@@ -136,8 +124,6 @@
     private final DirectMappedDexApplication application;
     private final Iterable<? extends ProguardConfigurationRule> rules;
     private final MutableItemsWithRules noShrinking = new MutableItemsWithRules();
-    private final Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo =
-        new IdentityHashMap<>();
     private final Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>>
         dependentMinimumKeepInfo = new HashMap<>();
     private final LinkedHashMap<DexReference, DexReference> reasonAsked = new LinkedHashMap<>();
@@ -401,7 +387,6 @@
           : "A method cannot be marked as both -neverinline and -forceinline/-alwaysinline.";
       return new RootSet(
           noShrinking,
-          minimumKeepInfo,
           dependentMinimumKeepInfo,
           ImmutableList.copyOf(reasonAsked.values()),
           ImmutableList.copyOf(checkDiscarded.values()),
@@ -497,7 +482,6 @@
           neverInlineDueToSingleCaller,
           neverClassInline,
           noShrinking,
-          minimumKeepInfo,
           dependentMinimumKeepInfo,
           dependentNoShrinking,
           dependentKeepClassCompatRule,
@@ -686,8 +670,7 @@
                   }
                   DexProgramClass precondition =
                       testAndGetPrecondition(methodToKeep.getDefinition(), preconditionSupplier);
-                  rootSetBuilder.addItemToSets(
-                      methodToKeep.getDefinition(), context, rule, precondition, ifRule);
+                  rootSetBuilder.addItemToSets(methodToKeep, context, rule, precondition, ifRule);
                 }));
       }
     }
@@ -1094,7 +1077,7 @@
           if (methodsMarked != null) {
             methodsMarked.add(MethodSignatureEquivalence.get().wrap(method.getReference()));
           }
-          addItemToSets(method.getDefinition(), context, rule, precondition, ifRule);
+          addItemToSets(method, context, rule, precondition, ifRule);
         }
       }
     }
@@ -1110,7 +1093,7 @@
           if (Log.ENABLED) {
             Log.verbose(getClass(), "Marking field `%s` due to `%s { %s }`.", field, context, rule);
           }
-          addItemToSets(field.getDefinition(), context, rule, precondition, ifRule);
+          addItemToSets(field, context, rule, precondition, ifRule);
         }
       }
     }
@@ -1124,7 +1107,7 @@
 
     // TODO(b/192636793): This needs to use the precondition.
     private void includeDescriptor(
-        DexDefinition item,
+        ProgramDefinition item,
         DexType type,
         ProguardKeepRuleBase context,
         DexProgramClass precondition) {
@@ -1149,187 +1132,58 @@
 
       // Disable minification for the type.
       if (appView.options().isMinificationEnabled()) {
-        modifyMinimumKeepInfo(minimumKeepInfo, clazz, Joiner::disallowMinification);
+        modifyDependentMinimumKeepInfo(
+            dependentMinimumKeepInfo,
+            UnconditionalKeepInfoEvent.get(),
+            clazz,
+            Joiner::disallowMinification);
       }
     }
 
     private void includeDescriptorClasses(
-        DexDefinition item, ProguardKeepRuleBase context, DexProgramClass precondition) {
-      if (item.isDexEncodedMethod()) {
-        DexEncodedMethod method = item.asDexEncodedMethod();
-        includeDescriptor(item, method.getReturnType(), context, precondition);
+        ProgramDefinition item, ProguardKeepRuleBase context, DexProgramClass precondition) {
+      if (item.isMethod()) {
+        ProgramMethod method = item.asProgramMethod();
+        includeDescriptor(method, method.getReturnType(), context, precondition);
         for (DexType value : method.getParameters()) {
-          includeDescriptor(item, value, context, precondition);
+          includeDescriptor(method, value, context, precondition);
         }
-      } else if (item.isDexEncodedField()) {
-        DexEncodedField field = item.asDexEncodedField();
-        includeDescriptor(item, field.getType(), context, precondition);
+      } else if (item.isField()) {
+        ProgramField field = item.asProgramField();
+        includeDescriptor(field, field.getType(), context, precondition);
       } else {
-        assert item.isDexClass();
+        assert item.isClass();
       }
     }
 
     private synchronized void addItemToSets(
-        DexDefinition item,
+        Definition item,
         ProguardConfigurationRule context,
         ProguardMemberRule rule,
         DexProgramClass precondition,
         ProguardIfRule ifRule) {
       if (context instanceof ProguardKeepRule) {
-        if (item.isDexEncodedField()) {
-          DexEncodedField encodedField = item.asDexEncodedField();
-          if (encodedField.getOptimizationInfo().cannotBeKept()) {
-            // We should only ever get here with if rules.
-            assert ifRule != null;
-            return;
-          }
-        } else if (item.isDexEncodedMethod()) {
-          DexEncodedMethod encodedMethod = item.asDexEncodedMethod();
-          if (encodedMethod.isClassInitializer() && !options.debug) {
-            // Don't keep class initializers.
-            return;
-          }
-          if (encodedMethod.getOptimizationInfo().cannotBeKept()) {
-            // We should only ever get here with if rules.
-            assert ifRule != null;
-            return;
-          }
-          if (options.isGeneratingDex()
-              && encodedMethod.getReference().isLambdaDeserializeMethod(appView.dexItemFactory())) {
-            // Don't keep lambda deserialization methods.
-            return;
-          }
-          // If desugaring is enabled, private and static interface methods will be moved to a
-          // companion class. So we don't need to add them to the root set in the beginning.
-          if (options.isInterfaceMethodDesugaringEnabled()
-              && encodedMethod.hasCode()
-              && (encodedMethod.isPrivateMethod() || encodedMethod.isStaticMember())) {
-            DexClass holder = appView.definitionFor(encodedMethod.getHolderType());
-            if (holder != null && holder.isInterface()) {
-              if (rule.isSpecific()) {
-                options.reporter.warning(
-                    new StringDiagnostic(
-                        "The rule `"
-                            + rule
-                            + "` is ignored because the targeting interface method `"
-                            + encodedMethod.getReference().toSourceString()
-                            + "` will be desugared."));
-              }
-              return;
-            }
-          }
-        }
-
-        // The reason for keeping should link to the conditional rule as a whole, if present.
-        ProguardKeepRuleBase keepRule = ifRule != null ? ifRule : (ProguardKeepRuleBase) context;
-
-        // The modifiers are specified on the actual keep rule (ie, the consequent/context).
-        ProguardKeepRuleModifiers modifiers = ((ProguardKeepRule) context).getModifiers();
-        if (modifiers.isBottom()) {
-          // This rule is a no-op.
+        if (!item.isProgramDefinition()) {
+          // Keep rules do not apply to non-program items.
           return;
         }
-
-        // In compatibility mode, for a match on instance members a referenced class becomes live.
-        if (options.forceProguardCompatibility
-            && !modifiers.allowsShrinking
-            && precondition != null
-            && precondition.isDexClass()) {
-          if (!item.isDexClass() && !item.isStaticMember()) {
-            dependentKeepClassCompatRule
-                .computeIfAbsent(precondition.asDexClass().getType(), i -> new HashSet<>())
-                .add(keepRule);
-            context.markAsUsed();
-          }
-        }
-
-        // TODO(b/192636793): Remove the noShrinking and dependentNoShrinking collections. A
-        //  prerequisite for this is that the ProguardKeepRule instances are added to the KeepInfo,
-        //  since this is needed for the -whyareyoukeeping graph.
-        if (!modifiers.allowsShrinking) {
-          if (precondition != null) {
-            dependentNoShrinking
-                .computeIfAbsent(precondition.getReference(), x -> new MutableItemsWithRules())
-                .addReferenceWithRule(item.getReference(), keepRule);
-          } else {
-            noShrinking.addReferenceWithRule(item.getReference(), keepRule);
-          }
-          context.markAsUsed();
-        }
-
-        EnqueuerEvent preconditionEvent;
-        if (precondition != null) {
-          preconditionEvent =
-              item.getAccessFlags().isStatic()
-                  ? new LiveClassEnqueuerEvent(precondition)
-                  : new InstantiatedClassEnqueuerEvent(precondition);
-        } else {
-          preconditionEvent = null;
-        }
-
-        if (appView.options().isAnnotationRemovalEnabled() && !modifiers.allowsAnnotationRemoval) {
-          if (precondition != null) {
-            modifyDependentMinimumKeepInfo(
-                dependentMinimumKeepInfo,
-                preconditionEvent,
-                item,
-                Joiner::disallowAnnotationRemoval);
-          } else {
-            modifyMinimumKeepInfo(minimumKeepInfo, item, Joiner::disallowAnnotationRemoval);
-          }
-          context.markAsUsed();
-        }
-
-        if (appView.options().isMinificationEnabled() && !modifiers.allowsObfuscation) {
-          if (precondition != null) {
-            modifyDependentMinimumKeepInfo(
-                dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowMinification);
-          } else {
-            modifyMinimumKeepInfo(minimumKeepInfo, item, Joiner::disallowMinification);
-          }
-          context.markAsUsed();
-        }
-
-        if (appView.options().isOptimizationEnabled() && !modifiers.allowsOptimization) {
-          if (precondition != null) {
-            modifyDependentMinimumKeepInfo(
-                dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowOptimization);
-          } else {
-            modifyMinimumKeepInfo(minimumKeepInfo, item, Joiner::disallowOptimization);
-          }
-          context.markAsUsed();
-        }
-
-        if (appView.options().isShrinking() && !modifiers.allowsShrinking) {
-          if (precondition != null) {
-            modifyDependentMinimumKeepInfo(
-                dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowShrinking);
-          } else {
-            modifyMinimumKeepInfo(minimumKeepInfo, item, Joiner::disallowShrinking);
-          }
-          context.markAsUsed();
-        }
-
-        if (modifiers.includeDescriptorClasses) {
-          includeDescriptorClasses(item, keepRule, precondition);
-          context.markAsUsed();
-        }
+        evaluateKeepRule(item.asProgramDefinition(), context, rule, precondition, ifRule);
       } else if (context instanceof ProguardAssumeMayHaveSideEffectsRule) {
         mayHaveSideEffects.put(item.getReference(), rule);
         context.markAsUsed();
       } else if (context instanceof ProguardAssumeNoSideEffectRule) {
-        if (item.isDexEncodedMember()) {
-          DexEncodedMember<?, ?> member = item.asDexEncodedMember();
+        if (item.isMember()) {
+          DexClassAndMember<?, ?> member = item.asMember();
           if (member.getHolderType() == appView.dexItemFactory().objectType) {
-            assert member.isDexEncodedMethod();
+            assert member.isMethod();
             reportAssumeNoSideEffectsWarningForJavaLangClassMethod(
-                member.asDexEncodedMethod(), (ProguardAssumeNoSideEffectRule) context);
+                member.asMethod(), (ProguardAssumeNoSideEffectRule) context);
           } else {
             noSideEffects.put(member.getReference(), rule);
-            if (member.isDexEncodedMethod()) {
-              DexEncodedMethod method = member.asDexEncodedMethod();
-              if (method.isClassInitializer()) {
-                feedback.classInitializerMayBePostponed(method);
+            if (member.isMethod()) {
+              DexClassAndMethod method = member.asMethod();
+              if (method.getDefinition().isClassInitializer()) {
+                feedback.classInitializerMayBePostponed(method.getDefinition());
               }
             }
           }
@@ -1339,16 +1193,16 @@
         reasonAsked.computeIfAbsent(item.getReference(), i -> i);
         context.markAsUsed();
       } else if (context instanceof ProguardAssumeValuesRule) {
-        if (item.isDexEncodedMember()) {
-          assumedValues.put(item.asDexEncodedMember().getReference(), rule);
+        if (item.isMember()) {
+          assumedValues.put(item.asMember().getReference(), rule);
           context.markAsUsed();
         }
       } else if (context instanceof ProguardCheckDiscardRule) {
         checkDiscarded.computeIfAbsent(item.getReference(), i -> i);
         context.markAsUsed();
       } else if (context instanceof InlineRule) {
-        if (item.isDexEncodedMethod()) {
-          DexMethod reference = item.asDexEncodedMethod().getReference();
+        if (item.isMethod()) {
+          DexMethod reference = item.asMethod().getReference();
           switch (((InlineRule) context).getType()) {
             case ALWAYS:
               alwaysInline.add(reference);
@@ -1368,14 +1222,14 @@
           context.markAsUsed();
         }
       } else if (context instanceof WhyAreYouNotInliningRule) {
-        if (!item.isDexEncodedMethod()) {
+        if (!item.isMethod()) {
           throw new Unreachable();
         }
-        whyAreYouNotInlining.add(item.asDexEncodedMethod().getReference());
+        whyAreYouNotInlining.add(item.asMethod().getReference());
         context.markAsUsed();
       } else if (context.isClassInlineRule()) {
         ClassInlineRule classInlineRule = context.asClassInlineRule();
-        DexClass clazz = item.asDexClass();
+        DexClass clazz = item.asClass();
         if (clazz == null) {
           throw new IllegalStateException(
               "Unexpected -"
@@ -1386,39 +1240,39 @@
         }
         switch (classInlineRule.getType()) {
           case ALWAYS:
-            alwaysClassInline.addElement(item.asDexClass().type);
+            alwaysClassInline.addElement(item.asClass().getType());
             break;
           case NEVER:
-            neverClassInline.add(item.asDexClass().type);
+            neverClassInline.add(item.asClass().getType());
             break;
           default:
             throw new Unreachable();
         }
         context.markAsUsed();
       } else if (context instanceof NoUnusedInterfaceRemovalRule) {
-        noUnusedInterfaceRemoval.add(item.asDexClass().type);
+        noUnusedInterfaceRemoval.add(item.asClass().type);
         context.markAsUsed();
       } else if (context instanceof NoVerticalClassMergingRule) {
-        noVerticalClassMerging.add(item.asDexClass().type);
+        noVerticalClassMerging.add(item.asClass().type);
         context.markAsUsed();
       } else if (context instanceof NoHorizontalClassMergingRule) {
-        noHorizontalClassMerging.add(item.asDexClass().type);
+        noHorizontalClassMerging.add(item.asClass().type);
         context.markAsUsed();
       } else if (context instanceof MemberValuePropagationRule) {
         switch (((MemberValuePropagationRule) context).getType()) {
           case NEVER:
             // Only add members from propgram classes to `neverPropagateValue` since class member
             // values from library types are not propagated by default.
-            if (item.isDexEncodedField()) {
-              DexEncodedField field = item.asDexEncodedField();
-              if (field.isProgramField(appView)) {
-                neverPropagateValue.add(item.asDexEncodedField().getReference());
+            if (item.isField()) {
+              DexClassAndField field = item.asField();
+              if (field.isProgramField()) {
+                neverPropagateValue.add(field.getReference());
                 context.markAsUsed();
               }
-            } else if (item.isDexEncodedMethod()) {
-              DexEncodedMethod method = item.asDexEncodedMethod();
-              if (method.isProgramMethod(appView)) {
-                neverPropagateValue.add(item.asDexEncodedMethod().getReference());
+            } else if (item.isMethod()) {
+              DexClassAndMethod method = item.asMethod();
+              if (method.isProgramMethod()) {
+                neverPropagateValue.add(method.getReference());
                 context.markAsUsed();
               }
             }
@@ -1427,16 +1281,16 @@
             throw new Unreachable();
         }
       } else if (context instanceof ProguardIdentifierNameStringRule) {
-        if (item.isDexEncodedField()) {
-          identifierNameStrings.add(item.asDexEncodedField().getReference());
+        if (item.isField()) {
+          identifierNameStrings.add(item.asField().getReference());
           context.markAsUsed();
-        } else if (item.isDexEncodedMethod()) {
-          identifierNameStrings.add(item.asDexEncodedMethod().getReference());
+        } else if (item.isMethod()) {
+          identifierNameStrings.add(item.asMethod().getReference());
           context.markAsUsed();
         }
       } else if (context instanceof ConstantArgumentRule) {
-        if (item.isDexEncodedMethod()) {
-          keepParametersWithConstantValue.add(item.asDexEncodedMethod().getReference());
+        if (item.isMethod()) {
+          keepParametersWithConstantValue.add(item.asMethod().getReference());
           context.markAsUsed();
         }
       } else if (context instanceof ReprocessClassInitializerRule) {
@@ -1455,8 +1309,8 @@
           context.markAsUsed();
         }
       } else if (context.isReprocessMethodRule()) {
-        if (item.isDexEncodedMethod()) {
-          DexEncodedMethod method = item.asDexEncodedMethod();
+        if (item.isMethod()) {
+          DexClassAndMethod method = item.asMethod();
           switch (context.asReprocessMethodRule().getType()) {
             case ALWAYS:
               reprocess.add(method.getReference());
@@ -1470,8 +1324,8 @@
           context.markAsUsed();
         }
       } else if (context instanceof UnusedArgumentRule) {
-        if (item.isDexEncodedMethod()) {
-          keepUnusedArguments.add(item.asDexEncodedMethod().getReference());
+        if (item.isMethod()) {
+          keepUnusedArguments.add(item.asMethod().getReference());
           context.markAsUsed();
         }
       } else {
@@ -1479,8 +1333,135 @@
       }
     }
 
+    private synchronized void evaluateKeepRule(
+        ProgramDefinition item,
+        ProguardConfigurationRule context,
+        ProguardMemberRule rule,
+        DexProgramClass precondition,
+        ProguardIfRule ifRule) {
+      if (item.isField()) {
+        ProgramField field = item.asProgramField();
+        if (field.getOptimizationInfo().cannotBeKept()) {
+          // We should only ever get here with if rules.
+          assert ifRule != null;
+          return;
+        }
+      } else if (item.isMethod()) {
+        ProgramMethod method = item.asProgramMethod();
+        if (method.getDefinition().isClassInitializer() && !options.debug) {
+          // Don't keep class initializers.
+          return;
+        }
+        if (method.getOptimizationInfo().cannotBeKept()) {
+          // We should only ever get here with if rules.
+          assert ifRule != null;
+          return;
+        }
+        if (options.isGeneratingDex()
+            && method.getReference().isLambdaDeserializeMethod(appView.dexItemFactory())) {
+          // Don't keep lambda deserialization methods.
+          return;
+        }
+        // If desugaring is enabled, private and static interface methods will be moved to a
+        // companion class. So we don't need to add them to the root set in the beginning.
+        if (options.isInterfaceMethodDesugaringEnabled()
+            && method.getDefinition().hasCode()
+            && (method.getAccessFlags().isPrivate() || method.getAccessFlags().isStatic())) {
+          DexClass holder = appView.definitionFor(method.getHolderType());
+          if (holder != null && holder.isInterface()) {
+            if (rule.isSpecific()) {
+              options.reporter.warning(
+                  new StringDiagnostic(
+                      "The rule `"
+                          + rule
+                          + "` is ignored because the targeting interface method `"
+                          + method.getReference().toSourceString()
+                          + "` will be desugared."));
+            }
+            return;
+          }
+        }
+      }
+
+      // The reason for keeping should link to the conditional rule as a whole, if present.
+      ProguardKeepRuleBase keepRule = ifRule != null ? ifRule : (ProguardKeepRuleBase) context;
+
+      // The modifiers are specified on the actual keep rule (ie, the consequent/context).
+      ProguardKeepRuleModifiers modifiers = ((ProguardKeepRule) context).getModifiers();
+      if (modifiers.isBottom()) {
+        // This rule is a no-op.
+        return;
+      }
+
+      // In compatibility mode, for a match on instance members a referenced class becomes live.
+      if (options.forceProguardCompatibility
+          && !modifiers.allowsShrinking
+          && precondition != null
+          && precondition.isDexClass()) {
+        if (!item.isClass() && !item.getAccessFlags().isStatic()) {
+          dependentKeepClassCompatRule
+              .computeIfAbsent(precondition.asDexClass().getType(), i -> new HashSet<>())
+              .add(keepRule);
+          context.markAsUsed();
+        }
+      }
+
+      // TODO(b/192636793): Remove the noShrinking and dependentNoShrinking collections. A
+      //  prerequisite for this is that the ProguardKeepRule instances are added to the KeepInfo,
+      //  since this is needed for the -whyareyoukeeping graph.
+      if (!modifiers.allowsShrinking) {
+        if (precondition != null) {
+          dependentNoShrinking
+              .computeIfAbsent(precondition.getReference(), x -> new MutableItemsWithRules())
+              .addReferenceWithRule(item.getReference(), keepRule);
+        } else {
+          noShrinking.addReferenceWithRule(item.getReference(), keepRule);
+        }
+        context.markAsUsed();
+      }
+
+      EnqueuerEvent preconditionEvent;
+      if (precondition != null) {
+        preconditionEvent =
+            item.getAccessFlags().isStatic()
+                ? new LiveClassEnqueuerEvent(precondition)
+                : new InstantiatedClassEnqueuerEvent(precondition);
+      } else {
+        preconditionEvent = UnconditionalKeepInfoEvent.get();
+      }
+
+      if (appView.options().isAnnotationRemovalEnabled() && !modifiers.allowsAnnotationRemoval) {
+        modifyDependentMinimumKeepInfo(
+            dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowAnnotationRemoval);
+        context.markAsUsed();
+      }
+
+      if (appView.options().isMinificationEnabled() && !modifiers.allowsObfuscation) {
+        modifyDependentMinimumKeepInfo(
+            dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowMinification);
+        context.markAsUsed();
+      }
+
+      if (appView.options().isOptimizationEnabled() && !modifiers.allowsOptimization) {
+        modifyDependentMinimumKeepInfo(
+            dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowOptimization);
+        context.markAsUsed();
+      }
+
+      if (appView.options().isShrinking() && !modifiers.allowsShrinking) {
+        modifyDependentMinimumKeepInfo(
+            dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowShrinking);
+        context.markAsUsed();
+      }
+
+      if (modifiers.includeDescriptorClasses) {
+        includeDescriptorClasses(item, keepRule, precondition);
+        context.markAsUsed();
+      }
+    }
+
     private void reportAssumeNoSideEffectsWarningForJavaLangClassMethod(
-        DexEncodedMethod method, ProguardAssumeNoSideEffectRule context) {
+        DexClassAndMethod method, ProguardAssumeNoSideEffectRule context) {
       assert method.getHolderType() == options.dexItemFactory().objectType;
       OriginWithPosition key = new OriginWithPosition(context.getOrigin(), context.getPosition());
       assumeNoSideEffectsWarnings
@@ -1527,7 +1508,6 @@
     final Set<DexMethod> neverInlineDueToSingleCaller;
     final Set<DexType> neverClassInline;
     final MutableItemsWithRules noShrinking;
-    final Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo;
     final Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo;
     final Map<DexReference, MutableItemsWithRules> dependentNoShrinking;
     final Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule;
@@ -1538,7 +1518,6 @@
         Set<DexMethod> neverInlineDueToSingleCaller,
         Set<DexType> neverClassInline,
         MutableItemsWithRules noShrinking,
-        Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo,
         Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo,
         Map<DexReference, MutableItemsWithRules> dependentNoShrinking,
         Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule,
@@ -1547,7 +1526,6 @@
       this.neverInlineDueToSingleCaller = neverInlineDueToSingleCaller;
       this.neverClassInline = neverClassInline;
       this.noShrinking = noShrinking;
-      this.minimumKeepInfo = minimumKeepInfo;
       this.dependentMinimumKeepInfo = dependentMinimumKeepInfo;
       this.dependentNoShrinking = dependentNoShrinking;
       this.dependentKeepClassCompatRule = dependentKeepClassCompatRule;
@@ -1664,8 +1642,6 @@
         TriConsumer<EnqueuerEvent, DexProgramClass, KeepClassInfo.Joiner> classConsumer,
         TriConsumer<EnqueuerEvent, ProgramField, KeepFieldInfo.Joiner> fieldConsumer,
         TriConsumer<EnqueuerEvent, ProgramMethod, KeepMethodInfo.Joiner> methodConsumer) {
-      internalForEachMinimumKeepInfo(
-          appView, minimumKeepInfo, null, classConsumer, fieldConsumer, methodConsumer);
       dependentMinimumKeepInfo.forEach(
           (precondition, minimumKeepInfoForDependents) ->
               internalForEachMinimumKeepInfo(
@@ -1996,7 +1972,6 @@
 
     private RootSet(
         MutableItemsWithRules noShrinking,
-        Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo,
         Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo,
         ImmutableList<DexReference> reasonAsked,
         ImmutableList<DexReference> checkDiscarded,
@@ -2029,7 +2004,6 @@
           neverInlineDueToSingleCaller,
           neverClassInline,
           noShrinking,
-          minimumKeepInfo,
           dependentMinimumKeepInfo,
           dependentNoShrinking,
           dependentKeepClassCompatRule,
@@ -2139,8 +2113,12 @@
           });
     }
 
-    void shouldNotBeMinified(DexReference reference) {
-      modifyMinimumKeepInfo(minimumKeepInfo, reference, Joiner::disallowMinification);
+    void shouldNotBeMinified(ProgramDefinition definition) {
+      modifyDependentMinimumKeepInfo(
+          dependentMinimumKeepInfo,
+          UnconditionalKeepInfoEvent.get(),
+          definition,
+          Joiner::disallowMinification);
     }
 
     public boolean verifyKeptFieldsAreAccessedAndLive(AppInfoWithLiveness appInfo) {
@@ -2335,7 +2313,6 @@
         Set<DexMethod> neverInlineDueToSingleCaller,
         Set<DexType> neverClassInline,
         MutableItemsWithRules noShrinking,
-        Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo,
         Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo,
         Map<DexReference, MutableItemsWithRules> dependentNoShrinking,
         Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule,
@@ -2345,7 +2322,6 @@
           neverInlineDueToSingleCaller,
           neverClassInline,
           noShrinking,
-          minimumKeepInfo,
           dependentMinimumKeepInfo,
           dependentNoShrinking,
           dependentKeepClassCompatRule,
@@ -2400,7 +2376,6 @@
       super(
           noShrinking,
           emptyMap(),
-          emptyMap(),
           reasonAsked,
           checkDiscarded,
           Collections.emptySet(),
@@ -2450,7 +2425,7 @@
     }
 
     @Override
-    void shouldNotBeMinified(DexReference reference) {
+    void shouldNotBeMinified(ProgramDefinition definition) {
       // Do nothing.
     }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index df989fe..276d737 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -36,6 +36,7 @@
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
+import java.util.function.Function;
 import java.util.function.Predicate;
 
 public class TreePruner {
@@ -195,21 +196,22 @@
     }
     clazz.removeInnerClasses(this::isAttributeReferencingMissingOrPrunedType);
     clazz.removeEnclosingMethodAttribute(this::isAttributeReferencingPrunedItem);
-    rewriteNestAttributes(clazz);
+    rewriteNestAttributes(clazz, this::isTypeLive, appView::definitionFor);
     unusedItemsPrinter.visited();
     assert verifyNoDeadFields(clazz);
   }
 
-  private void rewriteNestAttributes(DexProgramClass clazz) {
-    if (!clazz.isInANest() || !isTypeLive(clazz.type)) {
+  public static void rewriteNestAttributes(
+      DexProgramClass clazz, Predicate<DexType> isLive, Function<DexType, DexClass> definition) {
+    if (!clazz.isInANest() || !isLive.test(clazz.type)) {
       return;
     }
     if (clazz.isNestHost()) {
-      clearDeadNestMembers(clazz);
+      clearDeadNestMembers(clazz, isLive, definition);
     } else {
       assert clazz.isNestMember();
-      if (!isTypeLive(clazz.getNestHost())) {
-        claimNestOwnership(clazz);
+      if (!isLive.test(clazz.getNestHost())) {
+        claimNestOwnership(clazz, isLive, definition);
       }
     }
   }
@@ -222,26 +224,28 @@
     return appView.appInfo().isNonProgramTypeOrLiveProgramType(type);
   }
 
-  private void clearDeadNestMembers(DexClass nestHost) {
+  private static void clearDeadNestMembers(
+      DexClass nestHost, Predicate<DexType> isLive, Function<DexType, DexClass> definition) {
     // null definition should raise a warning which is raised later on in Nest specific passes.
     nestHost
         .getNestMembersClassAttributes()
         .removeIf(
             nestMemberAttr ->
-                appView.definitionFor(nestMemberAttr.getNestMember()) != null
-                    && !isTypeLive(nestMemberAttr.getNestMember()));
+                definition.apply(nestMemberAttr.getNestMember()) != null
+                    && !isLive.test(nestMemberAttr.getNestMember()));
   }
 
-  private void claimNestOwnership(DexClass newHost) {
-    DexClass previousHost = appView.definitionFor(newHost.getNestHost());
+  private static void claimNestOwnership(
+      DexClass newHost, Predicate<DexType> isLive, Function<DexType, DexClass> definition) {
+    DexClass previousHost = definition.apply(newHost.getNestHost());
     if (previousHost == null) {
       // Nest host will be cleared from all nest members in Nest specific passes.
       return;
     }
     newHost.clearNestHost();
     for (NestMemberClassAttribute attr : previousHost.getNestMembersClassAttributes()) {
-      if (attr.getNestMember() != newHost.type && isTypeLive(attr.getNestMember())) {
-        DexClass nestMember = appView.definitionFor(attr.getNestMember());
+      if (attr.getNestMember() != newHost.type && isLive.test(attr.getNestMember())) {
+        DexClass nestMember = definition.apply(attr.getNestMember());
         if (nestMember != null) {
           nestMember.setNestHost(newHost.type);
         }
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 061eb02..8bd2f01 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.ir.code.Invoke.Type.DIRECT;
 import static com.android.tools.r8.ir.code.Invoke.Type.STATIC;
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
 
 import com.android.tools.r8.androidapi.AndroidApiReferenceLevelCache;
 import com.android.tools.r8.errors.Unreachable;
@@ -441,11 +442,9 @@
     // Only merge if api reference level of source class is equal to target class.
     if (appView.options().apiModelingOptions().enableApiCallerIdentification) {
       AndroidApiLevel sourceApiLevel =
-          sourceClass.getApiReferenceLevel(
-              appView.options().minApiLevel, apiReferenceLevelCache::lookupMax);
+          sourceClass.getApiReferenceLevel(appView, apiReferenceLevelCache::lookupMax);
       AndroidApiLevel targetApiLevel =
-          targetClass.getApiReferenceLevel(
-              appView.options().minApiLevel, apiReferenceLevelCache::lookupMax);
+          targetClass.getApiReferenceLevel(appView, apiReferenceLevelCache::lookupMax);
       if (sourceApiLevel != targetApiLevel) {
         if (Log.ENABLED) {
           AbortReason.API_REFERENCE_LEVEL.printLogMessageForClass(sourceClass);
@@ -1441,7 +1440,9 @@
               ParameterAnnotationsList.empty(),
               code,
               true,
-              method.hasClassFileVersion() ? method.getClassFileVersion() : null);
+              method.hasClassFileVersion() ? method.getClassFileVersion() : null,
+              getApiLevelIfEnabledForNewMember(appView, method::getApiReferenceLevelForDefinition),
+              getApiLevelIfEnabledForNewMember(appView, Function.identity()));
       bridge.setLibraryMethodOverride(method.isLibraryMethodOverride());
       if (method.accessFlags.isPromotedToPublic()) {
         // The bridge is now the public method serving the role of the original method, and should
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
index e2cd6eb..adc3f40 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
@@ -16,6 +16,7 @@
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import java.util.function.Consumer;
 
 public class SyntheticMethodBuilder {
@@ -115,7 +116,9 @@
             parameterAnnotationsList,
             accessFlags.isAbstract() ? null : getCodeObject(methodSignature),
             isCompilerSynthesized,
-            classFileVersion);
+            classFileVersion,
+            AndroidApiLevel.UNKNOWN,
+            AndroidApiLevel.UNKNOWN);
     assert isValidSyntheticMethod(method, syntheticKind);
     if (onBuildConsumer != null) {
       onBuildConsumer.accept(method);
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
new file mode 100644
index 0000000..9272066
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
@@ -0,0 +1,48 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
+import java.util.function.Function;
+
+public class AndroidApiLevelUtils {
+
+  // Static api-level indicating that the api level is min-api.
+  public static final AndroidApiLevel MIN_API_LEVEL = null;
+
+  public static AndroidApiLevel getApiLevelIfEnabledForNewMember(
+      AppView<?> appView, Function<AndroidApiLevel, AndroidApiLevel> getter) {
+    AndroidApiLevel apiLevelIfEnabled = getApiLevelIfEnabled(appView, getter);
+    if (apiLevelIfEnabled == appView.options().minApiLevel) {
+      return MIN_API_LEVEL;
+    }
+    return apiLevelIfEnabled;
+  }
+
+  public static AndroidApiLevel getApiLevelIfEnabled(
+      AppView<?> appView, Function<AndroidApiLevel, AndroidApiLevel> getter) {
+    if (!appView.options().apiModelingOptions().enableApiCallerIdentification) {
+      return AndroidApiLevel.UNKNOWN;
+    }
+    return getter.apply(appView.options().minApiLevel);
+  }
+
+  public static OptionalBool isApiSafeForInlining(
+      ProgramMethod caller, ProgramMethod inlinee, InternalOptions options) {
+    if (!options.apiModelingOptions().enableApiCallerIdentification) {
+      return OptionalBool.TRUE;
+    }
+    if (caller.getHolderType() == inlinee.getHolderType()) {
+      return OptionalBool.TRUE;
+    }
+    return OptionalBool.of(
+        caller
+            .getDefinition()
+            .getApiReferenceLevel(options.minApiLevel)
+            .isGreaterThanOrEqualTo(
+                inlinee.getDefinition().getApiReferenceLevelForCode(options.minApiLevel)));
+  }
+}
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 c17a6ac..0a9c18a 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -618,6 +618,10 @@
     return forceProguardCompatibility;
   }
 
+  public boolean parseSignatureAttribute() {
+    return proguardConfiguration == null || isKeepAttributesSignatureEnabled();
+  }
+
   @Override
   public boolean isKeepAttributesSignatureEnabled() {
     return proguardConfiguration.getKeepAttributes().signature;
@@ -1342,6 +1346,7 @@
     public BiConsumer<MethodReference, AndroidApiLevel> tracedMethodApiLevelCallback = null;
 
     public boolean enableApiCallerIdentification = false;
+    public boolean checkAllApiReferencesAreSet = true;
 
     public void visitMockedApiReferences(BiConsumer<ClassReference, AndroidApiClass> consumer) {
       if (methodApiMapping.isEmpty() && fieldApiMapping.isEmpty() && classApiMapping.isEmpty()) {
@@ -1543,6 +1548,7 @@
     public boolean enableTestAssertions =
         System.getProperty("com.android.tools.r8.enableTestAssertions") != null;
     public boolean testEnableTestAssertions = false;
+    public boolean keepMetadataInR8IfNotRewritten = true;
 
     public boolean allowConflictingSyntheticTypes = false;
 
diff --git a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
index 468c1e9..33152f1 100644
--- a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
+++ b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
@@ -12,7 +12,9 @@
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
 import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.structural.Ordered;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -28,16 +30,22 @@
 
 public class KotlinCompilerTool {
 
-  public enum KotlinCompilerVersion {
+  public enum KotlinCompilerVersion implements Ordered<KotlinCompilerVersion> {
     KOTLINC_1_3_72("kotlin-compiler-1.3.72"),
     KOTLINC_1_4_20("kotlin-compiler-1.4.20"),
     KOTLINC_1_5_0("kotlin-compiler-1.5.0");
 
+    public static final KotlinCompilerVersion MIN_SUPPORTED_VERSION = KOTLINC_1_4_20;
+
     private final String folder;
 
     KotlinCompilerVersion(String folder) {
       this.folder = folder;
     }
+
+    public static KotlinCompilerVersion latest() {
+      return ArrayUtils.last(values());
+    }
   }
 
   public static final class KotlinCompiler {
diff --git a/src/test/java/com/android/tools/r8/KotlinTestParameters.java b/src/test/java/com/android/tools/r8/KotlinTestParameters.java
index 7cfcc07..4306e53 100644
--- a/src/test/java/com/android/tools/r8/KotlinTestParameters.java
+++ b/src/test/java/com/android/tools/r8/KotlinTestParameters.java
@@ -3,13 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
-import static org.junit.Assert.assertNotNull;
-
 import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
 import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
 import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Predicate;
 
 public class KotlinTestParameters {
 
@@ -55,13 +54,23 @@
 
   public static class Builder {
 
-    private KotlinCompiler[] compilers;
-    private KotlinTargetVersion[] targetVersions;
+    private Predicate<KotlinCompilerVersion> compilerFilter = c -> false;
+    private Predicate<KotlinTargetVersion> targetVersionFilter = t -> false;
 
     private Builder() {}
 
+    private Builder withCompilerFilter(Predicate<KotlinCompilerVersion> predicate) {
+      compilerFilter = compilerFilter.or(predicate);
+      return this;
+    }
+
+    private Builder withTargetVersionFilter(Predicate<KotlinTargetVersion> predicate) {
+      targetVersionFilter = targetVersionFilter.or(predicate);
+      return this;
+    }
+
     public Builder withAllCompilers() {
-      compilers = ToolHelper.getKotlinCompilers();
+      withCompilerFilter(compiler -> true);
       return this;
     }
 
@@ -69,41 +78,46 @@
       return withAllCompilers().withAllTargetVersions();
     }
 
-    public Builder withCompiler(KotlinCompiler compiler) {
-      compilers = new KotlinCompiler[] {compiler};
+    public Builder withCompiler(KotlinCompilerVersion compilerVersion) {
+      withCompilerFilter(c -> c.isEqualTo(compilerVersion));
       return this;
     }
 
     public Builder withAllTargetVersions() {
-      targetVersions = KotlinTargetVersion.values();
+      withTargetVersionFilter(t -> true);
       return this;
     }
 
     public Builder withTargetVersion(KotlinTargetVersion targetVersion) {
-      targetVersions = new KotlinTargetVersion[] {targetVersion};
+      withTargetVersionFilter(t -> t.equals(targetVersion));
+      return this;
+    }
+
+    public Builder withCompilersStartingFromIncluding(KotlinCompilerVersion version) {
+      withCompilerFilter(c -> c.isGreaterThanOrEqualTo(version));
       return this;
     }
 
     public KotlinTestParametersCollection build() {
-      validate();
       List<KotlinTestParameters> testParameters = new ArrayList<>();
       int index = 0;
-      for (KotlinCompiler kotlinc : compilers) {
-        for (KotlinTargetVersion targetVersion : targetVersions) {
+      for (KotlinCompilerVersion kotlinVersion : KotlinCompilerVersion.values()) {
+        for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
           // KotlinTargetVersion java 6 is deprecated from kotlinc 1.5 and forward, no need to run
           // tests on that target.
-          if (targetVersion != KotlinTargetVersion.JAVA_6
-              || kotlinc.isNot(KotlinCompilerVersion.KOTLINC_1_5_0)) {
-            testParameters.add(new KotlinTestParameters(kotlinc, targetVersion, index++));
+          if (targetVersion == KotlinTargetVersion.JAVA_6
+              && kotlinVersion.equals(KotlinCompilerVersion.KOTLINC_1_5_0)) {
+            continue;
+          }
+          if (compilerFilter.test(kotlinVersion) && targetVersionFilter.test(targetVersion)) {
+            testParameters.add(
+                new KotlinTestParameters(
+                    new KotlinCompiler(kotlinVersion), targetVersion, index++));
           }
         }
       }
+      assert !testParameters.isEmpty();
       return new KotlinTestParametersCollection(testParameters);
     }
-
-    private void validate() {
-      assertNotNull(compilers);
-      assertNotNull(targetVersions);
-    }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index d41987d..e75ab6c 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -56,6 +56,7 @@
 import com.android.tools.r8.shaking.ProguardClassNameList;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.shaking.ProguardKeepRule;
 import com.android.tools.r8.shaking.ProguardKeepRule.Builder;
 import com.android.tools.r8.shaking.ProguardKeepRuleType;
@@ -735,17 +736,17 @@
         MainDexInfo.none());
   }
 
-  protected static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierachy(
+  protected static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierarchy(
       AndroidApp app) throws Exception {
-    return computeAppViewWithClassHierachy(app, null);
+    return computeAppViewWithClassHierarchy(app, null);
   }
 
-  private static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierachy(
+  protected static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierarchy(
       AndroidApp app, Function<DexItemFactory, ProguardConfiguration> keepConfig) throws Exception {
-    return computeAppViewWithClassHierachy(app, keepConfig, null);
+    return computeAppViewWithClassHierarchy(app, keepConfig, null);
   }
 
-  private static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierachy(
+  private static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierarchy(
       AndroidApp app,
       Function<DexItemFactory, ProguardConfiguration> keepConfig,
       Consumer<InternalOptions> optionsConsumer)
@@ -753,9 +754,13 @@
     DexItemFactory dexItemFactory = new DexItemFactory();
     if (keepConfig == null) {
       keepConfig =
-          factory ->
-              buildConfigForRules(
-                  factory, ImmutableList.of(ProguardKeepRule.defaultKeepAllRule(unused -> {})));
+          factory -> {
+            ProguardConfiguration.Builder builder =
+                ProguardConfiguration.builder(factory, new Reporter());
+            builder.addRule(ProguardKeepRule.defaultKeepAllRule(unused -> {}));
+            builder.addKeepAttributePatterns(ImmutableList.of(ProguardKeepAttributes.SIGNATURE));
+            return builder.build();
+          };
     }
     InternalOptions options = new InternalOptions(keepConfig.apply(dexItemFactory), new Reporter());
     if (optionsConsumer != null) {
@@ -791,7 +796,7 @@
       Consumer<InternalOptions> optionsConsumer)
       throws Exception {
     AppView<AppInfoWithClassHierarchy> appView =
-        computeAppViewWithClassHierachy(app, keepConfig, optionsConsumer);
+        computeAppViewWithClassHierarchy(app, keepConfig, optionsConsumer);
     // Run the tree shaker to compute an instance of AppInfoWithLiveness.
     ExecutorService executor = Executors.newSingleThreadExecutor();
     SubtypingInfo subtypingInfo = new SubtypingInfo(appView);
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGenerator.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGenerator.java
index 9aa8f4d..dfaecd1 100644
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGenerator.java
+++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGenerator.java
@@ -36,6 +36,7 @@
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
+import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.Opcodes;
 
@@ -102,7 +103,8 @@
               .removeMethods(MethodPredicate.onName("placeHolderForGetMemberCount"))
               .removeMethods(MethodPredicate.onName("placeHolderForVisitFields"))
               .removeMethods(MethodPredicate.onName("placeHolderForVisitMethods"))
-              .transform());
+              .computeMaxs()
+              .transform(ClassWriter.COMPUTE_MAXS));
     }
 
     for (String pkg : packages) {
@@ -112,7 +114,8 @@
               .setClassDescriptor(getPackageBuilderDescriptor(pkg))
               .addMethodTransformer(getBuildClassTransformer(packageToClassesMap.get(pkg)))
               .removeMethods(MethodPredicate.onName("placeHolder"))
-              .transform());
+              .computeMaxs()
+              .transform(ClassWriter.COMPUTE_MAXS));
     }
 
     consumer.accept(
@@ -123,7 +126,8 @@
             .addMethodTransformer(getBuildPackageTransformer(packages))
             .removeMethods(MethodPredicate.onName("placeHolderForVisitApiClasses"))
             .removeMethods(MethodPredicate.onName("placeHolderForBuildClass"))
-            .transform());
+            .computeMaxs()
+            .transform(ClassWriter.COMPUTE_MAXS));
   }
 
   private static String getPackageBuilderDescriptor(String pkg) {
@@ -179,7 +183,7 @@
   private static MethodTransformer getGetMemberCountTransformer(ParsedApiClass apiClass) {
     return replaceCode(
         "placeHolderForGetMemberCount",
-        transformer -> transformer.visitLdcInsn(apiClass.getMemberCount()));
+        transformer -> transformer.visitLdcInsn(apiClass.getTotalMemberCount()));
   }
 
   // The transformer below changes AndroidApiDatabaseClassTemplate.visitFields from:
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGeneratorTest.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGeneratorTest.java
index 6d46bfd..2ad1e72 100644
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGeneratorTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGeneratorTest.java
@@ -237,7 +237,7 @@
         apiClass -> {
           expected.add(apiClass.getClassReference().getDescriptor());
           expected.add(apiClass.getApiLevel().getName());
-          expected.add(apiClass.getMemberCount() + "");
+          expected.add(apiClass.getTotalMemberCount() + "");
           BooleanBox added = new BooleanBox(false);
           apiClass.visitFieldReferences(
               (apiLevel, fieldReferences) -> {
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java
index dbb71d3..4002bf9 100644
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java
+++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java
@@ -148,8 +148,19 @@
       return apiLevel;
     }
 
-    public int getMemberCount() {
-      return fieldReferences.size() + methodReferences.size();
+    /**
+     * getMemberCount() returns the total number of members present on the max api level, that is it
+     * is the disjoint union of all members for all api levels.
+     */
+    public int getTotalMemberCount() {
+      int count = 0;
+      for (List<FieldReference> value : fieldReferences.values()) {
+        count += value.size();
+      }
+      for (List<MethodReference> value : methodReferences.values()) {
+        count += value.size();
+      }
+      return count;
     }
 
     private void register(FieldReference reference, AndroidApiLevel apiLevel) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelBackportTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelBackportTest.java
new file mode 100644
index 0000000..e32a62e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelBackportTest.java
@@ -0,0 +1,95 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
+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.references.Reference;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.lang.reflect.Method;
+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 ApiModelBackportTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ApiModelBackportTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    // For dex runtimes the `callBackport` is always min-api, because we either:
+    // - backport `Integer.toUnsignedString` thus the code is program code
+    // - call the implementation in the library where min-api >= 0.
+    // For CF we do not desugar the call and thus have to keep it at the api level O.
+    Method callBackport = ApiCaller.class.getDeclaredMethod("callBackport", int.class);
+    testForR8(parameters.getBackend())
+        .addProgramClasses(ApiCaller.class, ApiCallerCaller.class, Main.class)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .apply(
+            addTracedApiReferenceLevelCallBack(
+                (method, apiLevel) -> {
+                  if (Reference.methodFromMethod(callBackport).equals(method)) {
+                    assertEquals(
+                        parameters.isCfRuntime() ? AndroidApiLevel.O : parameters.getApiLevel(),
+                        apiLevel);
+                  }
+                }))
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("0")
+        .inspect(
+            inspector -> {
+              if (parameters.isCfRuntime()) {
+                assertThat(inspector.clazz(ApiCaller.class), isPresent());
+                assertThat(inspector.clazz(Main.class), isPresent());
+                assertEquals(2, inspector.allClasses().size());
+              } else {
+                assertThat(inspector.clazz(ApiCaller.class), not(isPresent()));
+                assertThat(inspector.clazz(Main.class), isPresent());
+                assertEquals(1, inspector.allClasses().size());
+              }
+            });
+  }
+
+  public static class ApiCaller {
+
+    public static String callBackport(int length) {
+      return Integer.toUnsignedString(length);
+    }
+  }
+
+  public static class ApiCallerCaller {
+
+    public static String callCallBackport(int length) {
+      return ApiCaller.callBackport(length);
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      System.out.println(ApiCallerCaller.callCallBackport(args.length));
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiFieldsTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiFieldsTest.java
index cb837ac..18b35f5 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiFieldsTest.java
@@ -51,6 +51,7 @@
               }
             })
         .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .apply(ApiModelingTestHelper::disableCheckAllApiReferencesAreNotUnknown)
         .apply(setMockApiLevelForClass(Api.class, AndroidApiLevel.L_MR1))
         .compile()
         .addRunClasspathClasses(Api.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldSuperTypeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldSuperTypeTest.java
new file mode 100644
index 0000000..32b111e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldSuperTypeTest.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.lang.reflect.Method;
+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 ApiModelFieldSuperTypeTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ApiModelFieldSuperTypeTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test(expected = CompilationFailedException.class)
+  public void testR8() throws Exception {
+    Method main = Main.class.getDeclaredMethod("main", String[].class);
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(
+            transformer(Main.class)
+                .replaceClassDescriptorInMethodInstructions(
+                    descriptor(AccessibilityService.class),
+                    "Landroid/accessibilityservice/AccessibilityService;")
+                .transform())
+        .addLibraryFiles(
+            ToolHelper.getFirstSupportedAndroidJar(
+                parameters.isCfRuntime() ? AndroidApiLevel.B : parameters.getApiLevel()))
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .apply(
+            addTracedApiReferenceLevelCallBack(
+                (method, apiLevel) -> {
+                  if (Reference.methodFromMethod(main).equals(method)) {
+                    // TODO(b/193414761): Should not be UNKNOWN.
+                    assertEquals(AndroidApiLevel.UNKNOWN, apiLevel);
+                  }
+                }))
+        .compileWithExpectedDiagnostics(
+            diagnostics -> {
+              // TODO(b/193414761): We should analyze all members.
+              diagnostics.assertErrorMessageThatMatches(
+                  containsString("Every member should have been analyzed"));
+            });
+  }
+
+  /* Only here to get the test to compile */
+  public static class AccessibilityService {
+
+    int START_CONTINUATION_MASK = 42;
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      // START_CONTINUATION_MASK is inherited from android/app/Service which was introduced at
+      // AndroidApiLevel.B.
+      System.out.println(
+          new /* android.accessibilityservice */ AccessibilityService().START_CONTINUATION_MASK);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldTypeReferenceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldTypeReferenceTest.java
new file mode 100644
index 0000000..149c93e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldTypeReferenceTest.java
@@ -0,0 +1,97 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
+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.references.Reference;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.lang.reflect.Method;
+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 ApiModelFieldTypeReferenceTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ApiModelFieldTypeReferenceTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    Method readApiField = B.class.getDeclaredMethod("readApiField");
+    Method setApiField = B.class.getDeclaredMethod("setApiField", Object.class);
+    testForR8(parameters.getBackend())
+        .addProgramClasses(A.class, B.class, Main.class)
+        .addLibraryClasses(Api.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(setMockApiLevelForClass(Api.class, AndroidApiLevel.L_MR1))
+        .apply(setMockApiLevelForDefaultInstanceInitializer(Api.class, AndroidApiLevel.L_MR1))
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .apply(
+            addTracedApiReferenceLevelCallBack(
+                (method, apiLevel) -> {
+                  if (Reference.methodFromMethod(readApiField).equals(method)
+                      || Reference.methodFromMethod(setApiField).equals(method)) {
+                    if (parameters.isCfRuntime()) {
+                      assertEquals(AndroidApiLevel.L_MR1, apiLevel);
+                    } else {
+                      assertEquals(AndroidApiLevel.L_MR1.max(parameters.getApiLevel()), apiLevel);
+                    }
+                  }
+                }))
+        .compile()
+        .addRunClasspathClasses(Api.class)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("Api");
+  }
+
+  public static class Api {}
+
+  public static class A {
+
+    public static Api api;
+  }
+
+  public static class B {
+
+    public static void readApiField() {
+      System.out.println(A.api == null ? "null" : "Api");
+    }
+
+    public static void setApiField(Object obj) {
+      A.api = (Api) obj;
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      if (args.length > 0) {
+        B.setApiField(args[0]);
+      } else {
+        B.setApiField(new Api());
+      }
+      B.readApiField();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassDifferentApiLevelTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassDifferentApiLevelTest.java
new file mode 100644
index 0000000..8002d8c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassDifferentApiLevelTest.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+
+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.utils.AndroidApiLevel;
+import java.lang.reflect.Method;
+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 ApiModelInlineInSameClassDifferentApiLevelTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ApiModelInlineInSameClassDifferentApiLevelTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    Method apiLevel22 = Api.class.getDeclaredMethod("apiLevel22");
+    Method callApi = ApiCaller.class.getDeclaredMethod("callApi");
+    Method callCallApi = ApiCaller.class.getDeclaredMethod("callCallApi");
+    testForR8(parameters.getBackend())
+        .addProgramClasses(ApiCaller.class, Main.class)
+        .addLibraryClasses(Api.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(setMockApiLevelForMethod(apiLevel22, AndroidApiLevel.L_MR1))
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .enableInliningAnnotations()
+        .compile()
+        .inspect(verifyThat(parameters, callApi).inlinedInto(callCallApi))
+        .addRunClasspathClasses(Api.class)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("Api::apiLevel22");
+  }
+
+  public static class Api {
+
+    public static void apiLevel22() {
+      System.out.println("Api::apiLevel22");
+    }
+  }
+
+  public static class ApiCaller {
+
+    public static void callApi() {
+      Api.apiLevel22();
+    }
+
+    @NeverInline
+    public static void callCallApi() {
+      callApi();
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      ApiCaller.callCallApi();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMethodTypeReferenceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMethodTypeReferenceTest.java
new file mode 100644
index 0000000..d3d9572
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMethodTypeReferenceTest.java
@@ -0,0 +1,105 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
+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.references.Reference;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.lang.reflect.Method;
+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 ApiModelMethodTypeReferenceTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ApiModelMethodTypeReferenceTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    Method readApi = B.class.getDeclaredMethod("readApi");
+    Method setApi = B.class.getDeclaredMethod("setApi", Object.class);
+    testForR8(parameters.getBackend())
+        .addProgramClasses(A.class, B.class, Main.class)
+        .addLibraryClasses(Api.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(setMockApiLevelForClass(Api.class, AndroidApiLevel.L_MR1))
+        .apply(setMockApiLevelForDefaultInstanceInitializer(Api.class, AndroidApiLevel.L_MR1))
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .apply(
+            addTracedApiReferenceLevelCallBack(
+                (method, apiLevel) -> {
+                  if (Reference.methodFromMethod(readApi).equals(method)
+                      || Reference.methodFromMethod(setApi).equals(method)) {
+                    if (parameters.isCfRuntime()) {
+                      assertEquals(AndroidApiLevel.L_MR1, apiLevel);
+                    } else {
+                      assertEquals(AndroidApiLevel.L_MR1.max(parameters.getApiLevel()), apiLevel);
+                    }
+                  }
+                }))
+        .compile()
+        .addRunClasspathClasses(Api.class)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("Api");
+  }
+
+  public static class Api {}
+
+  public static class A {
+
+    private static Api api;
+
+    public static void setApi(Api api) {
+      A.api = api;
+    }
+
+    public static Api getApi() {
+      return A.api;
+    }
+  }
+
+  public static class B {
+
+    public static void readApi() {
+      System.out.println(A.getApi() == null ? "null" : "Api");
+    }
+
+    public static void setApi(Object obj) {
+      A.setApi((Api) obj);
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      if (args.length > 0) {
+        B.setApi(args[0]);
+      } else {
+        B.setApi(new Api());
+      }
+      B.readApi();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java
index 777b250..f4609d4 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.apimodel;
 
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForField;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.not;
@@ -47,12 +48,17 @@
         .enableInliningAnnotations()
         .enableNoHorizontalClassMergingAnnotations()
         .apply(setMockApiLevelForField(apiField, AndroidApiLevel.L_MR1))
+        .apply(setMockApiLevelForDefaultInstanceInitializer(Api.class, AndroidApiLevel.L_MR1))
         .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .compile()
         .inspect(
             inspector -> {
-              // TODO(b/138781768): Should not be class inlined.
-              assertThat(inspector.clazz(ApiCaller.class), not(isPresent()));
+              if (parameters.isDexRuntime()
+                  && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L_MR1)) {
+                assertThat(inspector.clazz(ApiCaller.class), not(isPresent()));
+              } else {
+                assertThat(inspector.clazz(ApiCaller.class), isPresent());
+              }
             })
         .addRunClasspathClasses(Api.class)
         .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java
index ac42465..22ecf86 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java
@@ -5,13 +5,15 @@
 package com.android.tools.r8.apimodel;
 
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
-import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
 
-import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.apimodel.ApiModelNoClassInliningFieldTest.ApiCallerCaller;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import java.lang.reflect.Method;
 import org.junit.Test;
@@ -36,8 +38,6 @@
   @Test
   public void testR8() throws Exception {
     Method apiMethod = Api.class.getDeclaredMethod("apiLevel22");
-    Method apiCaller = ApiCaller.class.getDeclaredMethod("callApi");
-    Method apiCallerCaller = ApiCallerCaller.class.getDeclaredMethod("callCallApi");
     testForR8(parameters.getBackend())
         .addProgramClasses(ApiCaller.class, ApiCallerCaller.class, Main.class)
         .addLibraryClasses(Api.class)
@@ -50,8 +50,14 @@
         .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .compile()
         .inspect(
-            verifyThat(parameters, apiCaller)
-                .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.L_MR1))
+            inspector -> {
+              if (parameters.isDexRuntime()
+                  && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L_MR1)) {
+                assertThat(inspector.clazz(ApiCaller.class), not(isPresent()));
+              } else {
+                assertThat(inspector.clazz(ApiCaller.class), isPresent());
+              }
+            })
         .addRunClasspathClasses(Api.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("Api::apiLevel22");
@@ -72,19 +78,10 @@
     }
   }
 
-  @NoHorizontalClassMerging
-  public static class ApiCallerCaller {
-
-    @NeverInline
-    public static void callCallApi() {
-      new ApiCaller().callApi();
-    }
-  }
-
   public static class Main {
 
     public static void main(String[] args) {
-      ApiCallerCaller.callCallApi();
+      new ApiCaller().callApi();
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java
index cd86ade..e997894 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java
@@ -6,8 +6,9 @@
 
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
 import static com.android.tools.r8.utils.AndroidApiLevel.L_MR1;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbstract;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.not;
+import static junit.framework.TestCase.assertEquals;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestBase;
@@ -15,6 +16,7 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeMatchers;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import java.lang.reflect.Method;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -46,26 +48,36 @@
         .addKeepMainRule(Main.class)
         .apply(setMockApiLevelForMethod(apiMethod, L_MR1))
         .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .noMinification()
         .compile()
         .inspect(
             inspector -> {
-              ClassSubject aSubject = inspector.clazz(A.class);
-              assertThat(aSubject, isPresent());
-              aSubject.forAllMethods(
-                  method -> {
-                    // TODO(b/191013385): noApiCall is inlined into Main, but the synthesized
-                    //  A.callApiLevel that dispatches to $CC is not. This should change after
-                    //  desugaring is moved up to the enqueuer.
-                    if (method
-                            .getOriginalName()
-                            .equals(ApiCaller.class.getTypeName() + ".callApiLevel")
-                        && !method.getAccessFlags().isBridge()) {
-                      // TODO(b/191008231): Should not invoke api here.
-                      assertThat(method, CodeMatchers.invokesMethodWithName("apiLevel22"));
-                      return;
-                    }
-                    assertThat(method, not(CodeMatchers.invokesMethodWithName("apiLevel")));
-                  });
+              assertThat(inspector.clazz(Main.class), isPresent());
+              if (parameters.isDexRuntime()
+                  && parameters.getApiLevel().isGreaterThanOrEqualTo(L_MR1)) {
+                assertEquals(1, inspector.allClasses().size());
+              } else {
+                ClassSubject aSubject = inspector.clazz(A.class);
+                ClassSubject apiCaller = inspector.clazz(ApiCaller.class);
+                assertThat(apiCaller, isPresent());
+                MethodSubject callApiLevel = apiCaller.uniqueMethodWithName("callApiLevel");
+                if (parameters.isCfRuntime()) {
+                  assertThat(aSubject, isPresent());
+                  assertThat(callApiLevel, CodeMatchers.invokesMethodWithName("apiLevel22"));
+                } else {
+                  assert parameters.isDexRuntime();
+                  // TODO(b/191013385): A has a virtual method that calls callApiLevel on $CC, but
+                  //  that call should be inlined.
+                  assertThat(aSubject, isPresent());
+                  assertThat(callApiLevel, isAbstract());
+                  ClassSubject classSubject = apiCaller.toCompanionClass();
+                  assertThat(classSubject, isPresent());
+                  assertEquals(1, classSubject.allMethods().size());
+                  assertThat(
+                      classSubject.allMethods().get(0),
+                      CodeMatchers.invokesMethodWithName("apiLevel22"));
+                }
+              }
             })
         .addRunClasspathClasses(Api.class)
         .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java
index c8f7caa..0525cd5 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java
@@ -79,11 +79,9 @@
                 assertThat(apiCaller, not(isPresent()));
               } else {
                 assertThat(apiCaller, isPresent());
-                MethodSubject apiCaller$lambdagetAction$0 =
-                    apiCaller.uniqueMethodWithName("lambda$getAction$0");
-                assertThat(apiCaller$lambdagetAction$0, isPresent());
-                assertThat(
-                    apiCaller$lambdagetAction$0, CodeMatchers.invokesMethodWithName("apiLevel22"));
+                MethodSubject callApi = apiCaller.uniqueMethodWithName("callApi");
+                assertThat(callApi, isPresent());
+                assertThat(callApi, CodeMatchers.invokesMethodWithName("apiLevel22"));
               }
             })
         .addRunClasspathClasses(Api.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java
index f01e1b0..98b4e92 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java
@@ -17,9 +17,9 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeMatchers;
 import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
 import java.lang.reflect.Method;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -70,12 +70,12 @@
                   && parameters.getApiLevel().isGreaterThanOrEqualTo(L_MR1)) {
                 assertThat(base, not(isPresent()));
                 ClassSubject sub = inspector.clazz(Sub.class);
-                List<FoundMethodSubject> callApis =
-                    sub.allMethods(
-                        method ->
-                            method.getOriginalName().equals(Base.class.getTypeName() + ".callApi"));
-                // TODO(b/191013233): Remove synthetic bridge. Remove noMinification after fixed.
-                assertEquals(2, callApis.size());
+                assertThat(sub, isPresent());
+                assertThat(sub.uniqueInstanceInitializer(), isPresent());
+                assertEquals(1, sub.virtualMethods().size());
+                FoundMethodSubject callCallApi = sub.virtualMethods().get(0);
+                assertEquals("callCallApi", callCallApi.getOriginalName());
+                assertThat(callCallApi, CodeMatchers.invokesMethodWithName("apiLevel22"));
               } else {
                 assertThat(base, isPresent());
               }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java
index b29e694..b7cd0b1 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java
@@ -17,9 +17,9 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeMatchers;
 import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
 import java.lang.reflect.Method;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -61,7 +61,6 @@
                 inspector.assertNoClassesMerged();
               }
             })
-        .noMinification()
         .compile()
         .inspect(
             inspector -> {
@@ -70,12 +69,12 @@
                   && parameters.getApiLevel().isGreaterThanOrEqualTo(L_MR1)) {
                 assertThat(base, not(isPresent()));
                 ClassSubject sub = inspector.clazz(Sub.class);
-                List<FoundMethodSubject> callApis =
-                    sub.allMethods(
-                        method ->
-                            method.getOriginalName().equals(Base.class.getTypeName() + ".callApi"));
-                // TODO(b/191013233): Remove synthetic bridge. Remove noMinification after fixed.
-                assertEquals(2, callApis.size());
+                assertThat(sub, isPresent());
+                assertThat(sub.uniqueInstanceInitializer(), isPresent());
+                assertEquals(1, sub.virtualMethods().size());
+                FoundMethodSubject callCallApi = sub.virtualMethods().get(0);
+                assertEquals("callCallApi", callCallApi.getOriginalName());
+                assertThat(callCallApi, CodeMatchers.invokesMethodWithName("apiLevel22"));
               } else {
                 assertThat(base, isPresent());
               }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchInterfaceOverrideTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchInterfaceOverrideTest.java
new file mode 100644
index 0000000..d262834
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchInterfaceOverrideTest.java
@@ -0,0 +1,78 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack;
+import static com.android.tools.r8.utils.AndroidApiLevel.LATEST;
+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.ToolHelper;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.lang.reflect.Method;
+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 ApiModelVirtualDispatchInterfaceOverrideTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ApiModelVirtualDispatchInterfaceOverrideTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test()
+  public void testR8() throws Exception {
+    // android/content/res/AssetManager exists from AndroidApiLevel.B but in 21 it implements
+    // java/lang/AutoCloseable. However, close()V has always been defined, so the api level should
+    // always be min api.
+    Method main =
+        ApiModelVirtualDispatchSuperTypeTest.Main.class.getDeclaredMethod("main", String[].class);
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(
+            transformer(Main.class)
+                .replaceClassDescriptorInMethodInstructions(
+                    descriptor(AssetManager.class), "Landroid/content/res/AssetManager;")
+                .transform())
+        .addLibraryFiles(ToolHelper.getAndroidJar(LATEST))
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .apply(
+            addTracedApiReferenceLevelCallBack(
+                (method, apiLevel) -> {
+                  if (Reference.methodFromMethod(main).equals(method)) {
+                    assertEquals(
+                        parameters.isCfRuntime() ? AndroidApiLevel.B : parameters.getApiLevel(),
+                        apiLevel);
+                  }
+                }))
+        .compile();
+  }
+
+  public static class AssetManager {
+
+    public void close() {}
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) throws Exception {
+      AssetManager manager = null;
+      manager.close();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchInterfaceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchInterfaceTest.java
new file mode 100644
index 0000000..22c0702
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchInterfaceTest.java
@@ -0,0 +1,70 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack;
+import static com.android.tools.r8.utils.AndroidApiLevel.UNKNOWN;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.references.Reference;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+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 ApiModelVirtualDispatchInterfaceTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ApiModelVirtualDispatchInterfaceTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test(expected = CompilationFailedException.class)
+  public void testR8() throws Exception {
+    Method main = Main.class.getDeclaredMethod("main", String[].class);
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Main.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .apply(
+            addTracedApiReferenceLevelCallBack(
+                (method, apiLevel) -> {
+                  if (Reference.methodFromMethod(main).equals(method)) {
+                    // TODO(b/193414761): Should not be UNKNOWN.
+                    assertEquals(UNKNOWN, apiLevel);
+                  }
+                }))
+        .compileWithExpectedDiagnostics(
+            diagnostics -> {
+              // TODO(b/193414761): We should analyze all members.
+              diagnostics.assertErrorMessageThatMatches(
+                  containsString("Every member should have been analyzed"));
+            });
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      // Iterator is inherited from java/lang/Iterable which was introduced at AndroidApiLevel.B.
+      new ArrayList<>().iterator();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java
new file mode 100644
index 0000000..3f8bed1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack;
+import static com.android.tools.r8.utils.AndroidApiLevel.LATEST;
+import static com.android.tools.r8.utils.AndroidApiLevel.UNKNOWN;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.Reference;
+import java.lang.reflect.Method;
+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 ApiModelVirtualDispatchLinkInterfaceTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ApiModelVirtualDispatchLinkInterfaceTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test(expected = CompilationFailedException.class)
+  public void testR8() throws Exception {
+    // Landroid/view/accessibility/AccessibilityNodeInfo$AccessibilityAction; is introduced at api
+    // level 21 and on api level 30 it implements android.os.Parcelable.
+    // android.os.Parcelable.describeContents() has api level B. Since the invoke goes through the
+    // link established at level 30, the api reference level should be 30.
+    Method main = Main.class.getDeclaredMethod("main", String[].class);
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(
+            transformer(Main.class)
+                .replaceClassDescriptorInMethodInstructions(
+                    descriptor(AccessibilityNodeInfo$AccessibilityAction.class),
+                    "Landroid/view/accessibility/AccessibilityNodeInfo$AccessibilityAction;")
+                .transform())
+        .addLibraryFiles(ToolHelper.getAndroidJar(LATEST))
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .apply(
+            addTracedApiReferenceLevelCallBack(
+                (method, apiLevel) -> {
+                  if (Reference.methodFromMethod(main).equals(method)) {
+                    // TODO(b/193414761): Should be 30.
+                    assertEquals(UNKNOWN, apiLevel);
+                  }
+                }))
+        .compileWithExpectedDiagnostics(
+            diagnostics -> {
+              // TODO(b/193414761): We should analyze all members.
+              diagnostics.assertErrorMessageThatMatches(
+                  containsString("Every member should have been analyzed"));
+            });
+  }
+
+  public static class AccessibilityNodeInfo$AccessibilityAction {
+    int describeContents() {
+      return 42;
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      new AccessibilityNodeInfo$AccessibilityAction().describeContents();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchSuperTypeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchSuperTypeTest.java
new file mode 100644
index 0000000..2c5868e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchSuperTypeTest.java
@@ -0,0 +1,83 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.lang.reflect.Method;
+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 ApiModelVirtualDispatchSuperTypeTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ApiModelVirtualDispatchSuperTypeTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test(expected = CompilationFailedException.class)
+  public void testR8() throws Exception {
+    Method main = Main.class.getDeclaredMethod("main", String[].class);
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(
+            transformer(Main.class)
+                .replaceClassDescriptorInMethodInstructions(
+                    descriptor(AccessibilityService.class),
+                    "Landroid/accessibilityservice/AccessibilityService;")
+                .transform())
+        .addLibraryFiles(
+            ToolHelper.getFirstSupportedAndroidJar(
+                parameters.isCfRuntime() ? AndroidApiLevel.B : parameters.getApiLevel()))
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .apply(
+            addTracedApiReferenceLevelCallBack(
+                (method, apiLevel) -> {
+                  if (Reference.methodFromMethod(main).equals(method)) {
+                    // TODO(b/193414761): Should not be UNKNOWN.
+                    assertEquals(AndroidApiLevel.UNKNOWN, apiLevel);
+                  }
+                }))
+        .compileWithExpectedDiagnostics(
+            diagnostics -> {
+              // TODO(b/193414761): We should analyze all members.
+              diagnostics.assertErrorMessageThatMatches(
+                  containsString("Every member should have been analyzed"));
+            });
+  }
+
+  /* Only here to get the test to compile */
+  public static class AccessibilityService {
+
+    public void stopSelf() {}
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      // stopSelf() is inherited from android/app/Service which was introduced at AndroidApiLevel.B.
+      new /* android.accessibilityservice */ AccessibilityService().stopSelf();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
index 4e02aff..76a4d56 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
@@ -89,6 +89,14 @@
         });
   }
 
+  static void disableCheckAllApiReferencesAreNotUnknown(
+      TestCompilerBuilder<?, ?, ?, ?, ?> compilerBuilder) {
+    compilerBuilder.addOptionsModification(
+        options -> {
+          options.apiModelingOptions().checkAllApiReferencesAreSet = false;
+        });
+  }
+
   static <T extends TestCompilerBuilder<?, ?, ?, ?, ?>>
       ThrowableConsumer<T> addTracedApiReferenceLevelCallBack(
           BiConsumer<MethodReference, AndroidApiLevel> consumer) {
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 c7544d5..f0f4e90 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
@@ -9,6 +9,7 @@
 import static org.hamcrest.CoreMatchers.startsWith;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 
 import com.android.tools.r8.L8Command;
 import com.android.tools.r8.OutputMode;
@@ -17,8 +18,11 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import org.junit.Assume;
@@ -104,6 +108,21 @@
     }
     assertThat(inspector.clazz("j$.util.Optional"), isPresent());
     assertThat(inspector.clazz("j$.util.function.Function"), isPresent());
+    if (parameters.getApiLevel().isLessThan(AndroidApiLevel.K)) {
+      inspector.forAllClasses(clazz -> clazz.forAllMethods(this::assertNoSupressedInvocations));
+    }
+  }
+
+  private void assertNoSupressedInvocations(FoundMethodSubject method) {
+    if (method.isAbstract()) {
+      return;
+    }
+    for (InstructionSubject instruction : method.instructions()) {
+      if (instruction.isInvoke() && instruction.getMethod() != null) {
+        assertNotEquals(
+            instruction.getMethod(), new DexItemFactory().throwableMethods.addSuppressed);
+      }
+    }
   }
 
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
index 6453792..f75e870 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
@@ -158,14 +158,16 @@
                   builder.inspectDiagnosticMessages(
                       diagnostics ->
                           assertTrue(
-                              diagnostics.getInfos().stream()
-                                  .noneMatch(
-                                      string ->
-                                          string
-                                              .getDiagnosticMessage()
-                                              .startsWith(
-                                                  "Invalid parameter counts in MethodParameter"
-                                                      + " attributes.")))))
+                              // TODO(b/193597730): Fix JDK11 desugared library message,
+                              isJDK11DesugaredLibrary()
+                                  || diagnostics.getInfos().stream()
+                                      .noneMatch(
+                                          string ->
+                                              string
+                                                  .getDiagnosticMessage()
+                                                  .startsWith(
+                                                      "Invalid parameter counts in MethodParameter"
+                                                          + " attributes.")))))
           .writeToZip();
     } catch (CompilationFailedException | ExecutionException | IOException e) {
       throw new RuntimeException(e);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
index c7fc371..c10af51 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompileResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
@@ -146,7 +147,11 @@
         testBuilder
             .compile()
             .assertNoErrorMessages()
-            .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
+            // -keepattributes Signature is added in kotlin-reflect from version 1.4.20.
+            .applyIf(
+                kotlinParameters.getCompiler().isNot(KOTLINC_1_3_72),
+                TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation,
+                TestCompileResult::assertNoInfoMessages)
             .apply(KotlinMetadataTestBase::verifyExpectedWarningsFromKotlinReflectAndStdLib);
     if (desugarLibrary) {
       assertNotNull(keepRuleConsumer);
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureCorrectnessHelperTests.java b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureCorrectnessHelperTests.java
index 969a59f..588ad23 100644
--- a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureCorrectnessHelperTests.java
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureCorrectnessHelperTests.java
@@ -8,6 +8,7 @@
 import static org.junit.Assert.assertNotNull;
 
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestDiagnosticMessagesImpl;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
@@ -17,8 +18,12 @@
 import com.android.tools.r8.graph.GenericSignatureContextBuilder;
 import com.android.tools.r8.graph.GenericSignatureCorrectnessHelper;
 import com.android.tools.r8.graph.GenericSignatureCorrectnessHelper.SignatureEvaluationResult;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.ProguardConfiguration;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
 import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import org.junit.Test;
@@ -41,12 +46,18 @@
   @Test
   public void testAllValid() throws Exception {
     AppView<AppInfoWithClassHierarchy> appView =
-        computeAppViewWithClassHierachy(
+        computeAppViewWithClassHierarchy(
             buildInnerClasses(GenericSignatureCorrectnessHelperTests.class)
                 .addLibraryFile(ToolHelper.getJava8RuntimeJar())
-                .build());
-    GenericSignatureContextBuilder contextBuilder =
-        GenericSignatureContextBuilder.create(appView.appInfo().classes());
+                .build(),
+            factory -> {
+              ProguardConfiguration.Builder builder =
+                  ProguardConfiguration.builder(
+                      factory, new Reporter(new TestDiagnosticMessagesImpl()));
+              builder.addKeepAttributePatterns(ImmutableList.of(ProguardKeepAttributes.SIGNATURE));
+              return builder.build();
+            });
+    GenericSignatureContextBuilder contextBuilder = GenericSignatureContextBuilder.create(appView);
     GenericSignatureCorrectnessHelper.createForVerification(appView, contextBuilder)
         .run(appView.appInfo().classes());
   }
@@ -178,14 +189,20 @@
       Class<?> classToVerify,
       SignatureEvaluationResult expected)
       throws Exception {
-    AppView<AppInfoWithClassHierarchy> appView =
-        computeAppViewWithClassHierachy(
+    AppView<AppInfoWithLiveness> appView =
+        computeAppViewWithLiveness(
             buildClasses(classes)
                 .addClassProgramData(transformations)
                 .addLibraryFile(ToolHelper.getJava8RuntimeJar())
-                .build());
-    GenericSignatureContextBuilder contextBuilder =
-        GenericSignatureContextBuilder.create(appView.appInfo().classes());
+                .build(),
+            factory -> {
+              ProguardConfiguration.Builder builder =
+                  ProguardConfiguration.builder(
+                      factory, new Reporter(new TestDiagnosticMessagesImpl()));
+              builder.addKeepAttributePatterns(ImmutableList.of(ProguardKeepAttributes.SIGNATURE));
+              return builder.build();
+            });
+    GenericSignatureContextBuilder contextBuilder = GenericSignatureContextBuilder.create(appView);
     GenericSignatureCorrectnessHelper check =
         GenericSignatureCorrectnessHelper.createForInitialCheck(appView, contextBuilder);
     DexProgramClass clazz =
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataFirstToLatestTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataFirstToLatestTest.java
new file mode 100644
index 0000000..c030f80
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataFirstToLatestTest.java
@@ -0,0 +1,150 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.kotlin.metadata;
+
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertThrows;
+
+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.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import java.nio.file.Path;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/**
+ * Kotlin has limited support for metadata of older versions. In particular, kotlinc 1.5 has
+ * deprecated byte-code version which is expected by kotlinc 1.3. The expectation is that if we
+ * compile with kotlinc 1.3 and then compile with R8 with a new version of the kolin-metadata-jvm
+ * library, the kotlin library is no longer usable in kotlinc 1.3. However, it should be usable in
+ * kotlinc 1.5.
+ */
+@RunWith(Parameterized.class)
+public class MetadataFirstToLatestTest extends KotlinMetadataTestBase {
+
+  private final String EXPECTED = StringUtils.lines("foo");
+  private static final String PKG_LIB = PKG + ".crossinline_anon_lib";
+  private static final String PKG_APP = PKG + ".crossinline_anon_app";
+  private final TestParameters parameters;
+
+  private static final KotlinCompileMemoizer libJars =
+      getCompileMemoizer(
+          getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"));
+
+  @Parameterized.Parameters(name = "{0}, {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(),
+        getKotlinTestParameters()
+            .withCompiler(KotlinCompilerVersion.KOTLINC_1_3_72)
+            .withAllTargetVersions()
+            .build());
+  }
+
+  public MetadataFirstToLatestTest(
+      TestParameters parameters, KotlinTestParameters kotlinParameters) {
+    super(kotlinParameters);
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void smokeTest() throws Exception {
+    runTest(
+        KotlinCompilerVersion.KOTLINC_1_5_0,
+        libJars.getForConfiguration(kotlinc, targetVersion),
+        getKotlinStdlibJar(kotlinc));
+  }
+
+  @Test
+  public void testOnFirst() throws Exception {
+    Path libJar =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
+            .addKeepAllClassesRule()
+            .addKeepAllAttributes()
+            .addOptionsModification(
+                options -> {
+                  // Ensure that we rewrite the metadata with kotlin-metadata-jvm library.
+                  options.testing.keepMetadataInR8IfNotRewritten = false;
+                })
+            .compile()
+            .writeToZip();
+    Path stdLibJar =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(
+                ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinAnnotationJar(kotlinc))
+            .addKeepAllClassesRule()
+            .addKeepAllAttributes()
+            .allowDiagnosticWarningMessages()
+            .compile()
+            .assertAllWarningMessagesMatch(
+                equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
+            .writeToZip();
+    AssertionError assertionError =
+        assertThrows(
+            AssertionError.class,
+            () -> {
+              runTest(KotlinCompilerVersion.KOTLINC_1_3_72, libJar, stdLibJar);
+            });
+    assertThat(
+        assertionError.getMessage(),
+        containsString("compiled with an incompatible version of Kotlin"));
+  }
+
+  @Test
+  public void testOnLatest() throws Exception {
+    Path libJar =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
+            .addKeepAllClassesRule()
+            .addKeepAllAttributes()
+            .compile()
+            .writeToZip();
+    Path stdLibJar =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(
+                ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinAnnotationJar(kotlinc))
+            .addKeepAllClassesRule()
+            .addKeepAllAttributes()
+            .allowDiagnosticWarningMessages()
+            .compile()
+            .assertAllWarningMessagesMatch(
+                equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
+            .writeToZip();
+    runTest(KotlinCompilerVersion.KOTLINC_1_5_0, libJar, stdLibJar);
+  }
+
+  private void runTest(KotlinCompilerVersion kotlinCompilerVersion, Path libJar, Path stdLibJar)
+      throws Exception {
+    Path output =
+        kotlinc(
+                parameters.getRuntime().asCf(),
+                new KotlinCompiler(kotlinCompilerVersion),
+                targetVersion)
+            .addClasspathFiles(libJar, stdLibJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .noStdLib()
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(stdLibJar, libJar)
+        .addClasspath(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
index cfa333f..a9732a4 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -35,7 +36,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataPrimitiveTypeRewriteTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
index cccbde4..5c9a639 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -62,7 +63,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteAnnotationTest(
@@ -167,14 +171,14 @@
     assertEquals(
         DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB) + "/AnnoWithClassArr",
         annotation.getClassName());
-    Map<String, KmAnnotationArgument<?>> arguments = annotation.getArguments();
+    Map<String, KmAnnotationArgument> arguments = annotation.getArguments();
     assertEquals(1, arguments.size());
     ArrayValue classes = (ArrayValue) arguments.get("classes");
     assertEquals(
-        "KClassValue(value=" + foo.getFinalBinaryName() + ")",
-        classes.getValue().get(0).toString());
+        "KClassValue(className=" + foo.getFinalBinaryName() + ", arrayDimensionCount=0)",
+        classes.getElements().get(0).toString());
     assertEquals(
-        "KClassValue(value=" + bar.getFinalBinaryName() + ")",
-        classes.getValue().get(1).toString());
+        "KClassValue(className=" + bar.getFinalBinaryName() + ", arrayDimensionCount=0)",
+        classes.getElements().get(1).toString());
   }
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
index 0822971..03c8d5a 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -30,7 +31,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteAnonymousTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
index 2558cbb..08de164 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
@@ -49,7 +49,7 @@
     testForR8(parameters.getBackend())
         .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
-        .addKeepAllClassesRule()
+        .addKeepAllClassesRuleWithAllowObfuscation()
         .addKeepKotlinMetadata()
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
         .allowDiagnosticWarningMessages()
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
index 527269c..e37b5fd 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -43,7 +44,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteFlexibleUpperBoundTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
index 4c712d3..0785411 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
@@ -38,7 +39,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInClasspathTypeTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
index 0cedda8..6e754e1 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -47,7 +48,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInCompanionTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
index bc5f909..a95ed25 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -44,7 +45,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInExtensionFunctionTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
index 90e914d..c418067 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
@@ -43,7 +44,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInExtensionPropertyTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
index 24a19d3..14d1497 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
@@ -42,7 +43,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInFunctionTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
index ec249cb..c2c61a6 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
@@ -43,7 +44,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInFunctionWithVarargTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
index f2aa77d..24e7a56 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -36,7 +37,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInNestedClassTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
index 27ee400..59d3258 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -35,7 +36,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInParameterTypeTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
index 6bb1804..ebafde8 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.kotlin.metadata;
 
 import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_5_0;
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionProperty;
@@ -42,7 +43,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInPropertyTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
index 28721c8..e0233d9 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -35,7 +36,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInPropertyTypeTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
index 225ac74..ac35453 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -35,7 +36,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInReturnTypeTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java
index ccc94e5..ffa0888 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -35,7 +36,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInSuperTypeTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
index 0585af6..32be357 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinReflectJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
@@ -65,7 +66,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInTypeAliasTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
index eddf514..d5342de 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isDexClass;
@@ -42,8 +43,8 @@
 
   private static final String LIB_PKG = PKG + ".typeargument_lib.";
 
-  private static int FLAG_NONE = 0;
-  private static int FLAG_REIFIED = 1;
+  private static final int FLAG_NONE = 0;
+  private static final int FLAG_REIFIED = 1;
 
   private static final String EXPECTED =
       StringUtils.lines(
@@ -80,7 +81,10 @@
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewriteInTypeArgumentsTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
index 263b087..717bf12 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
@@ -11,11 +11,9 @@
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
-import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -45,30 +43,6 @@
     this.parameters = parameters;
   }
 
-  public int getExpectedAddedCount() {
-    if (kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_3_72)) {
-      return 597;
-    } else if (kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_4_20)) {
-      return 685;
-    } else if (kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_5_0)) {
-      return 696;
-    } else {
-      throw new Unreachable("Should not compile in this configuration");
-    }
-  }
-
-  public int getExpectedNonInitAddedCount() {
-    if (kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_3_72)) {
-      return 327;
-    } else if (kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_4_20)) {
-      return 413;
-    } else if (kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_5_0)) {
-      return 419;
-    } else {
-      throw new Unreachable("Should not compile in this configuration");
-    }
-  }
-
   @Test
   public void testKotlinStdLib() throws Exception {
     assumeFalse(parameters.isNoneRuntime());
@@ -90,8 +64,8 @@
                     new CodeInspector(getKotlinStdlibJar(kotlinc)),
                     inspector,
                     (addedStrings, addedNonInitStrings) -> {
-                      assertEquals(getExpectedAddedCount(), addedStrings.intValue());
-                      assertEquals(getExpectedNonInitAddedCount(), addedNonInitStrings.intValue());
+                      assertEquals(0, addedStrings.intValue());
+                      assertEquals(0, addedNonInitStrings.intValue());
                     }));
   }
 
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
index e59e318..9b8a8e7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static junit.framework.TestCase.assertEquals;
 import static org.hamcrest.CoreMatchers.not;
@@ -32,18 +33,17 @@
 
   private static final KotlinCompileMemoizer libJars =
       getCompileMemoizer(
-              getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
-          .configure(
-              kotlinCompilerTool -> {
-                kotlinCompilerTool.addClasspathFiles(ToolHelper.getClassPathForTests());
-              });
+          getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"));
   private final TestParameters parameters;
 
   @Parameterized.Parameters(name = "{0}, {1}")
   public static Collection<Object[]> data() {
     return buildParameters(
         getTestParameters().withCfRuntimes().build(),
-        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withAllTargetVersions()
+            .build());
   }
 
   public MetadataRewritePrunedObjectsTest(
@@ -74,13 +74,14 @@
     Path libJar =
         testForR8(parameters.getBackend())
             .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
-            .enableInliningAnnotations()
             .addClasspathFiles(
                 ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinAnnotationJar(kotlinc))
             .addKeepRules(
                 "-keep class " + PKG_LIB + ".Sub { <init>(); *** kept(); *** keptProperty; }")
+            .addKeepRules("-neverinline class * { @" + PKG_LIB + ".NeverInline *; }")
             .addKeepClassAndMembersRules(PKG_LIB + ".SubUser")
             .addKeepRuntimeVisibleAnnotations()
+            .enableProguardTestOptions()
             .noMinification()
             .compile()
             .inspect(this::checkPruned)
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteValueClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteValueClassTest.java
new file mode 100644
index 0000000..cc26b5c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteValueClassTest.java
@@ -0,0 +1,143 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.kotlin.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_5_0;
+import static com.android.tools.r8.ToolHelper.KotlinTargetVersion.JAVA_8;
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertNull;
+
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.kotlin.KotlinMetadataWriter;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collection;
+import junit.framework.TestCase;
+import kotlinx.metadata.jvm.KotlinClassHeader;
+import kotlinx.metadata.jvm.KotlinClassMetadata;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRewriteValueClassTest extends KotlinMetadataTestBase {
+
+  private static final String EXPECTED = StringUtils.lines("Hello, John Doe", "42", "UInt(x=42)");
+  private static final String PKG_LIB = PKG + ".value_class_lib";
+  private static final String PKG_APP = PKG + ".value_class_app";
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}, {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(),
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(KOTLINC_1_5_0)
+            .withTargetVersion(JAVA_8)
+            .build());
+  }
+
+  public MetadataRewriteValueClassTest(
+      TestParameters parameters, KotlinTestParameters kotlinParameters) {
+    super(kotlinParameters);
+    this.parameters = parameters;
+  }
+
+  private static final KotlinCompileMemoizer kotlincLibJar =
+      getCompileMemoizer(
+          getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"));
+
+  @Test
+  public void smokeTest() throws Exception {
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
+            .addClasspathFiles(kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(
+            getKotlinStdlibJar(kotlinc), kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
+        .addClasspath(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testMetadataForLib() throws Exception {
+    Path libJar =
+        testForR8(parameters.getBackend())
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
+            .addProgramFiles(kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
+            .addKeepAllClassesRule()
+            .addKeepAttributes(
+                ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS,
+                ProguardKeepAttributes.SIGNATURE,
+                ProguardKeepAttributes.INNER_CLASSES,
+                ProguardKeepAttributes.ENCLOSING_METHOD)
+            .addOptionsModification(
+                internalOptions -> {
+                  internalOptions.testing.keepMetadataInR8IfNotRewritten = false;
+                })
+            .compile()
+            .inspect(this::inspect)
+            .writeToZip();
+    Path main =
+        kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(
+            getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
+        .addClasspath(main)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  private void inspect(CodeInspector inspector) throws IOException {
+    CodeInspector stdLibInspector =
+        new CodeInspector(kotlincLibJar.getForConfiguration(kotlinc, targetVersion));
+    for (FoundClassSubject clazzSubject : stdLibInspector.allClasses()) {
+      ClassSubject r8Clazz = inspector.clazz(clazzSubject.getOriginalName());
+      assertThat(r8Clazz, isPresent());
+      KotlinClassMetadata originalMetadata = clazzSubject.getKotlinClassMetadata();
+      KotlinClassMetadata rewrittenMetadata = r8Clazz.getKotlinClassMetadata();
+      if (originalMetadata == null) {
+        assertNull(rewrittenMetadata);
+        continue;
+      }
+      TestCase.assertNotNull(rewrittenMetadata);
+      KotlinClassHeader originalHeader = originalMetadata.getHeader();
+      KotlinClassHeader rewrittenHeader = rewrittenMetadata.getHeader();
+      TestCase.assertEquals(originalHeader.getKind(), rewrittenHeader.getKind());
+      TestCase.assertEquals(originalHeader.getPackageName(), rewrittenHeader.getPackageName());
+      // We cannot assert equality of the data since it may be ordered differently. Instead we use
+      // the KotlinMetadataWriter.
+      String expected = KotlinMetadataWriter.kotlinMetadataToString("", originalMetadata);
+      String actual = KotlinMetadataWriter.kotlinMetadataToString("", rewrittenMetadata);
+      TestCase.assertEquals(expected, actual);
+      if (r8Clazz.getFinalName().equals(PKG_LIB + ".Name")) {
+        assertThat(actual, containsString("inlineClassUnderlyingPropertyName"));
+        assertThat(actual, containsString("inlineClassUnderlyingType"));
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java
index 4cf9124..b0ea3d9 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java
@@ -5,11 +5,11 @@
 package com.android.tools.r8.kotlin.metadata;
 
 import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
-import static com.android.tools.r8.ToolHelper.getKotlinC_1_3_72;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 import static org.objectweb.asm.Opcodes.ASM7;
 
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestParameters;
@@ -40,12 +40,12 @@
 
   private final TestParameters parameters;
 
-  @Parameters(name = "{0}")
+  @Parameters(name = "{0}, {1}")
   public static List<Object[]> data() {
     return buildParameters(
         getTestParameters().withAllRuntimesAndApiLevels().build(),
         getKotlinTestParameters()
-            .withCompiler(getKotlinC_1_3_72())
+            .withCompiler(KotlinCompilerVersion.KOTLINC_1_3_72)
             .withTargetVersion(KotlinTargetVersion.JAVA_8)
             .build());
   }
@@ -63,7 +63,8 @@
     testBuilder
         .addProgramFiles(getKotlinAnnotationJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
-        .addKeepAllClassesRule()
+        .addOptionsModification(options -> options.testing.keepMetadataInR8IfNotRewritten = false)
+        .addKeepAllClassesRuleWithAllowObfuscation()
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
         .compile()
         .inspect(inspector -> inspectMetadataVersion(inspector, "1.4.0"));
@@ -76,7 +77,7 @@
     testBuilder
         .addProgramFiles(getKotlinAnnotationJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
-        .addKeepAllClassesRule()
+        .addKeepAllClassesRuleWithAllowObfuscation()
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
         .compile()
         .inspect(inspector -> inspectMetadataVersion(inspector, "1.4.0"));
@@ -89,7 +90,7 @@
     testBuilder
         .addProgramFiles(getKotlinAnnotationJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
-        .addKeepAllClassesRule()
+        .addKeepAllClassesRuleWithAllowObfuscation()
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
         .compile()
         .inspect(inspector -> inspectMetadataVersion(inspector, "1.4.2"));
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_lib/lib.kt
index a7672fd..7cb8107 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_lib/lib.kt
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_lib/lib.kt
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.kotlin.metadata.pruned_lib
 
-import com.android.tools.r8.NeverInline
+annotation class NeverInline
 
 // The Base class will be removed during compilation
 open class Base
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/value_class_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/value_class_app/main.kt
new file mode 100644
index 0000000..476c6e1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/value_class_app/main.kt
@@ -0,0 +1,13 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.kotlin.metadata.value_class_app
+
+import com.android.tools.r8.kotlin.metadata.value_class_lib.*
+
+fun main() {
+  Name("John Doe").prettyPrint()
+  compute(42)
+  compute(UInt(42))
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/value_class_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/value_class_lib/lib.kt
new file mode 100644
index 0000000..0c4d392
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/value_class_lib/lib.kt
@@ -0,0 +1,39 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.kotlin.metadata.value_class_lib
+
+// These examples are from the kotlinlang.org website.
+
+interface Printable {
+  fun prettyPrint()
+}
+
+@JvmInline
+value class Name(val s: String) : Printable {
+
+  init {
+    require(s.length > 0) { }
+  }
+
+  val length: Int
+    get() = s.length
+
+  override fun prettyPrint() {
+    println("Hello, $s")
+  }
+}
+
+@JvmInline
+value class UInt(val x: Int)
+
+// Represented as 'public final void compute(int x)' on the JVM
+fun compute(x: Int) {
+  println(x);
+}
+
+// Also represented as 'public final void compute(int x)' on the JVM thus name is mangled!
+fun compute(x: UInt) {
+  println(x);
+}
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 6ee2517..d448e96 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
@@ -11,6 +11,7 @@
 import com.android.tools.r8.KotlinTestBase;
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompileResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.kotlin.metadata.KotlinMetadataTestBase;
@@ -96,7 +97,11 @@
         .allowUnusedDontWarnKotlinReflectJvmInternal(kotlinc.isNot(KOTLINC_1_3_72))
         .compile()
         .assertNoErrorMessages()
-        .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
+        // -keepattributes Signature is added in kotlin-reflect from version 1.4.20.
+        .applyIf(
+            kotlinParameters.getCompiler().isNot(KOTLINC_1_3_72),
+            TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation,
+            TestCompileResult::assertNoInfoMessages)
         .apply(KotlinMetadataTestBase::verifyExpectedWarningsFromKotlinReflectAndStdLib)
         .writeToZip(foo.toPath())
         .run(parameters.getRuntime(), PKG + ".SimpleReflectKt")
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 e5ed600..8410836 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
@@ -11,12 +11,12 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
 import com.android.tools.r8.KotlinTestBase;
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.TestRuntime.CfRuntime;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -41,8 +41,8 @@
     return buildParameters(
         getTestParameters().withDexRuntimes().withAllApiLevels().build(),
         getKotlinTestParameters()
+            .withCompiler(KotlinCompilerVersion.KOTLINC_1_5_0)
             .withTargetVersion(KotlinTargetVersion.JAVA_8)
-            .withCompiler(ToolHelper.getKotlinC_1_5_0())
             .build());
   }
 
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
index 62286f9..821bc4c 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
@@ -166,7 +166,7 @@
   }
 
   private AppView<AppInfoWithClassHierarchy> getAppView() throws Exception {
-    return computeAppViewWithClassHierachy(
+    return computeAppViewWithClassHierarchy(
         buildClasses(getClasses())
             .addClassProgramData(getTransformedClasses())
             .addLibraryFile(TestBase.runtimeJar(parameters.getBackend()))
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
index 20575adb..bec0f69 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
@@ -142,7 +142,7 @@
   }
 
   private AppView<AppInfoWithClassHierarchy> getAppView() throws Exception {
-    return computeAppViewWithClassHierachy(
+    return computeAppViewWithClassHierarchy(
         buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build());
   }
 
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
index 9286245..56258b4 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
@@ -175,7 +175,7 @@
   }
 
   private AppView<AppInfoWithClassHierarchy> getAppView() throws Exception {
-    return computeAppViewWithClassHierachy(
+    return computeAppViewWithClassHierarchy(
         buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build());
   }
 
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
index f6836fa..d630f6f 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
@@ -233,7 +233,7 @@
     // ----- Program -----
     // B extends A { } <-- initial
     AppView<AppInfoWithClassHierarchy> appView =
-        computeAppViewWithClassHierachy(
+        computeAppViewWithClassHierarchy(
             buildClasses(Collections.singletonList(B.class), Arrays.asList(A.class, I.class))
                 .build());
     AppInfoWithClassHierarchy appInfo = appView.appInfo();
diff --git a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
index 0169604..fb2db95 100644
--- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
+++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -56,9 +56,10 @@
   public static byte[] transform(
       byte[] bytes,
       List<ClassTransformer> classTransformers,
-      List<MethodTransformer> methodTransformers) {
+      List<MethodTransformer> methodTransformers,
+      int flags) {
     ClassReader reader = new ClassReader(bytes);
-    ClassWriter writer = new ClassWriter(reader, 0);
+    ClassWriter writer = new ClassWriter(reader, flags);
     ClassVisitor subvisitor = new InnerMostClassTransformer(writer, methodTransformers);
     for (int i = classTransformers.size() - 1; i >= 0; i--) {
       classTransformers.get(i).setSubVisitor(subvisitor);
@@ -144,7 +145,11 @@
   }
 
   public byte[] transform() {
-    return ClassFileTransformer.transform(bytes, classTransformers, methodTransformers);
+    return transform(0);
+  }
+
+  public byte[] transform(int flags) {
+    return ClassFileTransformer.transform(bytes, classTransformers, methodTransformers, flags);
   }
 
   /** Base addition of a transformer on the class. */
@@ -992,4 +997,14 @@
           }
         });
   }
+
+  public ClassFileTransformer computeMaxs() {
+    return addMethodTransformer(
+        new MethodTransformer() {
+          @Override
+          public void visitMaxs(int maxStack, int maxLocals) {
+            super.visitMaxs(maxStack, maxLocals);
+          }
+        });
+  }
 }
diff --git a/third_party/android_jar/api-database.tar.gz.sha1 b/third_party/android_jar/api-database.tar.gz.sha1
index 6336e23..97d5f12 100644
--- a/third_party/android_jar/api-database.tar.gz.sha1
+++ b/third_party/android_jar/api-database.tar.gz.sha1
@@ -1 +1 @@
-be72aeca006f1aba8b1fe4d9c3ff4c0e76259960
\ No newline at end of file
+a3e0351d71082eb74073576e11c0632191fd8530
\ No newline at end of file
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index cdceb6b..8667a9e 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -533,6 +533,9 @@
   if options.print_times:
     extra_args.append('-Dcom.android.tools.r8.printtimes=1')
 
+  if not options.no_debug:
+    extra_args.append('-Dcom.android.tools.r8.enableTestAssertions=1')
+
   outdir = options.out
   (version_id, data) = get_version_and_data(options)