Merge commit 'a8c6db61ad6808fb56c8cf61dfb1433814f40dc8' into dev-release
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index c1038e4..9fe678c 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -149,6 +149,15 @@
       }
     }
     builders {
+      name: "desugared_library_jdk11_head"
+      mixins: "linux"
+      mixins: "normal"
+      priority: 26
+      recipe {
+        properties_j: "test_options:[\"--no_internal\", \"--desugared-library\", \"HEAD\", \"--desugared-library-configuration\", \"jdk11\"]"
+      }
+    }
+    builders {
       name: "linux-dex-default"
       mixins: "linux"
       mixins: "normal"
diff --git a/infra/config/global/generated/cr-buildbucket.cfg b/infra/config/global/generated/cr-buildbucket.cfg
new file mode 100644
index 0000000..b8a3edb
--- /dev/null
+++ b/infra/config/global/generated/cr-buildbucket.cfg
@@ -0,0 +1,592 @@
+# Auto-generated by lucicfg.
+# Do not modify manually.
+#
+# For the schema of this file, see BuildbucketCfg message:
+#   https://luci-config.appspot.com/schemas/projects:buildbucket.cfg
+
+buckets {
+  name: "ci"
+  acls {
+    group: "all"
+  }
+  acls {
+    role: SCHEDULER
+    group: "luci-scheduler@appspot.gserviceaccount.com"
+  }
+  acls {
+    role: SCHEDULER
+    group: "project-r8-committers"
+  }
+  swarming {
+    builders {
+      name: "archive"
+      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: "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"
+      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:[\"--dex_vm=4.0.4\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android-4.0.4_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=4.0.4\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android-4.4.4"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=4.4.4\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android-4.4.4_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=4.4.4\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android-5.1.1"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=5.1.1\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android-5.1.1_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=5.1.1\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android-6.0.1"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=6.0.1\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android-6.0.1_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=6.0.1\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android-7.0.0"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=7.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android-7.0.0_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=7.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android=10.0.0"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=10.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android=10.0.0_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=10.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android=8.1.0"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=8.1.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android=8.1.0_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=8.1.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android=9.0.0"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=9.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-android=9.0.0_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--dex_vm=9.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-dex_default"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--runtimes=dex-default\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-dex_default_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--runtimes=dex-default\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      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: "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: "test_options:[\"--runtimes=jdk11\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      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: "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: "test_options:[\"--runtimes=jdk11\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-jdk11"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--runtimes=jdk11\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-jdk11_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--runtimes=jdk11\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-jdk8"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--runtimes=jdk8\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-jdk8_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--runtimes=jdk8\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-jdk9"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--runtimes=jdk9\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-jdk9_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--runtimes=jdk9\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-none"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--runtimes=none\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "linux-none_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      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: "test_options:[\"--runtimes=none\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "windows"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:windows-10"
+      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:[\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+    }
+    builders {
+      name: "windows_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:windows-10"
+      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:[\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+      }
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      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
new file mode 100644
index 0000000..3202e40
--- /dev/null
+++ b/infra/config/global/generated/luci-milo.cfg
@@ -0,0 +1,173 @@
+# Auto-generated by lucicfg.
+# Do not modify manually.
+#
+# For the schema of this file, see Project message:
+#   https://luci-config.appspot.com/schemas/projects:luci-milo.cfg
+
+consoles {
+  id: "main"
+  name: "R8 Main Console"
+  repo_url: "https://r8.googlesource.com/r8"
+  refs: "regexp:regexp:refs/heads/.*"
+  manifest_name: "REVISION"
+  builders {
+    name: "buildbucket/luci.r8.ci/archive"
+    category: "R8"
+    short_name: "archive"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/archive_release"
+    category: "R8"
+    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"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-internal_release"
+    category: "R8 release"
+    short_name: "internal"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-4.0.4"
+    category: "R8"
+    short_name: "4.0.4"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-4.0.4_release"
+    category: "R8 release"
+    short_name: "4.0.4"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-4.4.4"
+    category: "R8"
+    short_name: "4.4.4"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-4.4.4_release"
+    category: "R8 release"
+    short_name: "4.4.4"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-5.1.1"
+    category: "R8"
+    short_name: "5.1.1"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-5.1.1_release"
+    category: "R8 release"
+    short_name: "5.1.1"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-6.0.1"
+    category: "R8"
+    short_name: "6.0.1"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-6.0.1_release"
+    category: "R8 release"
+    short_name: "6.0.1"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-7.0.0"
+    category: "R8"
+    short_name: "7.0.0"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-7.0.0_release"
+    category: "R8 release"
+    short_name: "7.0.0"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android=8.1.0"
+    category: "R8"
+    short_name: "android=8.1.0"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android=8.1.0_release"
+    category: "R8 release"
+    short_name: "android=8.1.0"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android=9.0.0"
+    category: "R8"
+    short_name: "android=9.0.0"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android=9.0.0_release"
+    category: "R8 release"
+    short_name: "android=9.0.0"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android=10.0.0"
+    category: "R8"
+    short_name: "android=10.0.0"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android=10.0.0_release"
+    category: "R8 release"
+    short_name: "android=10.0.0"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/windows"
+    category: "R8"
+    short_name: "windows"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/windows_release"
+    category: "R8 release"
+    short_name: "windows"
+  }
+}
diff --git a/infra/config/global/generated/luci-notify.cfg b/infra/config/global/generated/luci-notify.cfg
new file mode 100644
index 0000000..24a7816
--- /dev/null
+++ b/infra/config/global/generated/luci-notify.cfg
@@ -0,0 +1,366 @@
+# Auto-generated by lucicfg.
+# Do not modify manually.
+#
+# For the schema of this file, see ProjectConfig message:
+#   https://luci-config.appspot.com/schemas/projects:luci-notify.cfg
+
+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"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android-4.0.4_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.4.4"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android-4.4.4_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android-5.1.1"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android-5.1.1_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android-6.0.1"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android-6.0.1_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android-7.0.0"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android-7.0.0_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android=10.0.0"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android=10.0.0_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android=8.1.0"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android=8.1.0_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android=9.0.0"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android=9.0.0_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-dex_default"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-dex_default_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-internal"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-internal_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-jdk11"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-jdk11_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-jdk8"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-jdk8_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-jdk9"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-jdk9_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-none"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-none_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "windows"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "windows_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
diff --git a/infra/config/global/generated/luci-scheduler.cfg b/infra/config/global/generated/luci-scheduler.cfg
new file mode 100644
index 0000000..72809c3
--- /dev/null
+++ b/infra/config/global/generated/luci-scheduler.cfg
@@ -0,0 +1,359 @@
+# Auto-generated by lucicfg.
+# Do not modify manually.
+#
+# For the schema of this file, see ProjectConfig message:
+#   https://luci-config.appspot.com/schemas/projects:luci-scheduler.cfg
+
+job {
+  id: "archive"
+  acl_sets: "ci"
+  triggering_policy {
+    kind: GREEDY_BATCHING
+    max_concurrent_invocations: 3
+    max_batch_size: 1
+  }
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "archive"
+  }
+}
+job {
+  id: "archive_release"
+  acl_sets: "ci"
+  triggering_policy {
+    kind: GREEDY_BATCHING
+    max_concurrent_invocations: 3
+    max_batch_size: 1
+  }
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "archive_release"
+  }
+}
+job {
+  id: "linux-android-4.0.4"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android-4.0.4"
+  }
+}
+job {
+  id: "linux-android-4.0.4_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android-4.0.4_release"
+  }
+}
+job {
+  id: "linux-android-4.4.4"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android-4.4.4"
+  }
+}
+job {
+  id: "linux-android-4.4.4_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android-4.4.4_release"
+  }
+}
+job {
+  id: "linux-android-5.1.1"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android-5.1.1"
+  }
+}
+job {
+  id: "linux-android-5.1.1_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android-5.1.1_release"
+  }
+}
+job {
+  id: "linux-android-6.0.1"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android-6.0.1"
+  }
+}
+job {
+  id: "linux-android-6.0.1_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android-6.0.1_release"
+  }
+}
+job {
+  id: "linux-android-7.0.0"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android-7.0.0"
+  }
+}
+job {
+  id: "linux-android-7.0.0_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android-7.0.0_release"
+  }
+}
+job {
+  id: "linux-android=10.0.0"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android=10.0.0"
+  }
+}
+job {
+  id: "linux-android=10.0.0_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android=10.0.0_release"
+  }
+}
+job {
+  id: "linux-android=8.1.0"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android=8.1.0"
+  }
+}
+job {
+  id: "linux-android=8.1.0_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android=8.1.0_release"
+  }
+}
+job {
+  id: "linux-android=9.0.0"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android=9.0.0"
+  }
+}
+job {
+  id: "linux-android=9.0.0_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-android=9.0.0_release"
+  }
+}
+job {
+  id: "linux-dex_default"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-dex_default"
+  }
+}
+job {
+  id: "linux-dex_default_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-dex_default_release"
+  }
+}
+job {
+  id: "linux-internal"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-internal"
+  }
+}
+job {
+  id: "linux-internal_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-internal_release"
+  }
+}
+job {
+  id: "linux-jdk11"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-jdk11"
+  }
+}
+job {
+  id: "linux-jdk11_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-jdk11_release"
+  }
+}
+job {
+  id: "linux-jdk8"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-jdk8"
+  }
+}
+job {
+  id: "linux-jdk8_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-jdk8_release"
+  }
+}
+job {
+  id: "linux-jdk9"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-jdk9"
+  }
+}
+job {
+  id: "linux-jdk9_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-jdk9_release"
+  }
+}
+job {
+  id: "linux-none"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-none"
+  }
+}
+job {
+  id: "linux-none_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "linux-none_release"
+  }
+}
+job {
+  id: "windows"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "windows"
+  }
+}
+job {
+  id: "windows_release"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "windows_release"
+  }
+}
+trigger {
+  id: "branch-gitiles-trigger"
+  acl_sets: "ci"
+  triggers: "archive_release"
+  triggers: "linux-android-4.0.4_release"
+  triggers: "linux-android-4.4.4_release"
+  triggers: "linux-android-5.1.1_release"
+  triggers: "linux-android-6.0.1_release"
+  triggers: "linux-android-7.0.0_release"
+  triggers: "linux-android=10.0.0_release"
+  triggers: "linux-android=8.1.0_release"
+  triggers: "linux-android=9.0.0_release"
+  triggers: "linux-dex_default_release"
+  triggers: "linux-internal_release"
+  triggers: "linux-jdk11_release"
+  triggers: "linux-jdk8_release"
+  triggers: "linux-jdk9_release"
+  triggers: "linux-none_release"
+  triggers: "windows_release"
+  gitiles {
+    repo: "https://r8.googlesource.com/r8"
+    refs: "regexp:regexp:refs/heads/(?:d8-)?[0-9]+\\.[0-9]+(\\.[0-9]+)?"
+    path_regexps: "src/main/java/com/android/tools/r8/Version.java"
+  }
+}
+trigger {
+  id: "main-gitiles-trigger"
+  acl_sets: "ci"
+  triggers: "archive"
+  triggers: "linux-android-4.0.4"
+  triggers: "linux-android-4.4.4"
+  triggers: "linux-android-5.1.1"
+  triggers: "linux-android-6.0.1"
+  triggers: "linux-android-7.0.0"
+  triggers: "linux-android=10.0.0"
+  triggers: "linux-android=8.1.0"
+  triggers: "linux-android=9.0.0"
+  triggers: "linux-dex_default"
+  triggers: "linux-internal"
+  triggers: "linux-jdk11"
+  triggers: "linux-jdk8"
+  triggers: "linux-jdk9"
+  triggers: "linux-none"
+  triggers: "windows"
+  gitiles {
+    repo: "https://r8.googlesource.com/r8"
+    refs: "regexp:refs/heads/master"
+  }
+}
+acl_sets {
+  name: "ci"
+  acls {
+    granted_to: "group:all"
+  }
+}
diff --git a/infra/config/global/generated/project.cfg b/infra/config/global/generated/project.cfg
new file mode 100644
index 0000000..97e5a27
--- /dev/null
+++ b/infra/config/global/generated/project.cfg
@@ -0,0 +1,8 @@
+# Auto-generated by lucicfg.
+# Do not modify manually.
+#
+# For the schema of this file, see ProjectCfg message:
+#   https://luci-config.appspot.com/schemas/projects:project.cfg
+
+name: "r8"
+access: "group:all"
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 5b0bb98..8218353 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -102,13 +102,18 @@
   }
   builders {
     name: "buildbucket/luci.r8.ci/archive_lib_desugar"
-    category: "archive_desugar"
-    short_name: "sdk_desugar"
+    category: "library_desugar"
+    short_name: "release"
   }
   builders {
     name: "buildbucket/luci.r8.ci/desugared_library_head"
-    category: "archive_desugar"
-    short_name: "head_desugar"
+    category: "library_desugar"
+    short_name: "head"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/desugared_library_jdk11_head"
+    category: "library_desugar"
+    short_name: "head_jdk11"
   }
   builders {
     name: "buildbucket/luci.r8.ci/archive_release"
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index d6c888e..4bd0b89 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -45,6 +45,7 @@
   triggers: "r8cf-linux-jctf"
   triggers: "windows"
   triggers: "desugared_library_head"
+  triggers: "desugared_library_jdk11_head"
 }
 
 trigger {
@@ -165,6 +166,19 @@
 }
 
 job {
+  id: "desugared_library_jdk11_head"
+  acl_sets: "default"
+  triggering_policy: {
+    max_concurrent_invocations: 1
+  }
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.r8.ci"
+    builder: "desugared_library_jdk11_head"
+  }
+}
+
+job {
   id: "kotlin-builder"
   acl_sets: "default"
   triggering_policy: {
diff --git a/infra/config/global/main.star b/infra/config/global/main.star
new file mode 100755
index 0000000..cdadb61
--- /dev/null
+++ b/infra/config/global/main.star
@@ -0,0 +1,209 @@
+#!/usr/bin/env lucicfg
+
+luci.project(
+    name = "r8",
+    buildbucket = "cr-buildbucket.appspot.com",
+    logdog = "luci-logdog.appspot.com",
+    milo = "luci-milo.appspot.com",
+    notify = "luci-notify.appspot.com",
+    scheduler = "luci-scheduler.appspot.com",
+    swarming = "chrome-swarming.appspot.com",
+    acls = [
+        acl.entry(
+            [
+                acl.BUILDBUCKET_READER,
+                acl.LOGDOG_READER,
+                acl.PROJECT_CONFIGS_READER,
+                acl.SCHEDULER_READER,
+            ],
+            groups = ["all"],
+        ),
+        acl.entry(
+            [
+                acl.BUILDBUCKET_TRIGGERER,
+            ],
+            groups = [
+                "luci-scheduler@appspot.gserviceaccount.com",
+                "project-r8-committers"
+    ],
+        ),
+
+    ]
+)
+
+luci.bucket(name = "ci")
+
+luci.milo()
+
+luci.notifier(
+  name = "r8-failures",
+  on_failure = True,
+  on_new_failure = True,
+  notify_blamelist = True
+)
+
+luci.gitiles_poller(
+  name = "main-gitiles-trigger",
+  bucket = "ci",
+  repo = "https://r8.googlesource.com/r8"
+)
+
+luci.gitiles_poller(
+  name = "branch-gitiles-trigger",
+  bucket = "ci",
+  repo = "https://r8.googlesource.com/r8",
+  # Version branches are named d8-x.y (up until d8-1.5) or just x.y (from 1.6)
+  refs = ["regexp:refs/heads/(?:d8-)?[0-9]+\\.[0-9]+(\\.[0-9]+)?"],
+  path_regexps = ["src/main/java/com/android/tools/r8/Version.java"]
+)
+
+luci.console_view(
+    name = "main",
+    title = "R8 Main Console",
+    repo = "https://r8.googlesource.com/r8",
+    refs = ["regexp:refs/heads/.*"]
+)
+
+def builder_view(name, category, short_name):
+    return luci.console_view_entry(
+        console_view = "main",
+        builder = name,
+        category = category,
+        short_name = short_name,
+    )
+
+luci.recipe(
+      name="rex",
+      cipd_package = "infra_internal/recipe_bundles/" +
+          "chrome-internal.googlesource.com/chrome/" +
+	  "tools/build_limited/scripts/slave",
+      cipd_version = "refs/heads/master"
+)
+
+common_test_options = [
+    "--tool=r8",
+    "--no_internal",
+    "--one_line_per_test",
+    "--archive_failures"
+]
+
+def get_dimensions(windows=False, jctf=False, internal=False):
+  dimensions = {
+    "cores" : "2" if internal else "8",
+    "cpu" : "x86-64",
+    "pool" : "luci.r8.ci"
+  }
+  if windows:
+    dimensions["os"] = "windows-10"
+  else:
+    dimensions["os"] = "Ubuntu-16.04"
+  if jctf:
+    dimensions["jctf"] = "true"
+  if internal:
+    dimensions["internal"] = "true"
+  return dimensions
+
+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])
+
+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")
+
+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")
+
+r8_tester_with_default("linux-dex_default", ["--runtimes=dex-default"])
+r8_tester_with_default("linux-none", ["--runtimes=none"])
+r8_tester_with_default("linux-jdk8", ["--runtimes=jdk8"])
+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",
+    ["--dex_vm=4.4.4", "--all_tests"])
+r8_tester_with_default("linux-android-5.1.1",
+    ["--dex_vm=5.1.1", "--all_tests"])
+r8_tester_with_default("linux-android-6.0.1",
+    ["--dex_vm=6.0.1", "--all_tests"])
+r8_tester_with_default("linux-android-7.0.0",
+    ["--dex_vm=7.0.0", "--all_tests"])
+r8_tester_with_default("linux-android=8.1.0",
+    ["--dex_vm=8.1.0", "--all_tests"])
+r8_tester_with_default("linux-android=9.0.0",
+    ["--dex_vm=9.0.0", "--all_tests"])
+r8_tester_with_default("linux-android=10.0.0",
+    ["--dex_vm=10.0.0", "--all_tests"])
+
+r8_tester_with_default("windows", ["--all_tests"],
+    dimensions=get_dimensions(windows=True))
diff --git a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
new file mode 100644
index 0000000..ad27516
--- /dev/null
+++ b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
@@ -0,0 +1,39 @@
+{
+  "configuration_format_version": 3,
+  "group_id" : "com.tools.android",
+  "artifact_id" : "chm_only_desugar_jdk_libs",
+  "version": "1.0.12",
+  "required_compilation_api_level": 26,
+  "synthesized_library_classes_package_prefix": "j$.",
+  "support_all_callbacks_from_library": false,
+  "common_flags": [
+  ],
+  "library_flags": [
+    {
+      "api_level_below_or_equal": 23,
+      "rewrite_prefix": {
+        "java.util.concurrent.Helpers": "j$.util.concurrent.Helpers",
+        "java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom",
+        "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap",
+        "sun.misc.Desugar": "j$.sun.misc.Desugar"
+      }
+    }
+  ],
+  "program_flags": [
+    {
+      "api_level_below_or_equal": 23,
+      "rewrite_prefix": {
+        "java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom",
+        "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap"
+      }
+    }
+  ],
+  "shrinker_config": [
+    "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }",
+    "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }",
+    "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$CounterCell { long value; }",
+    "-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }",
+    "-keeppackagenames j$",
+    "-dontwarn sun.misc.Unsafe"
+  ]
+}
\ No newline at end of file
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 9e1b306..5049ee4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -22,6 +22,7 @@
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.kotlin.KotlinFieldLevelInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.ConsumerUtils;
 import com.android.tools.r8.utils.structural.StructuralItem;
 import com.android.tools.r8.utils.structural.StructuralMapping;
@@ -127,6 +128,11 @@
     return optimizationInfo;
   }
 
+  @Override
+  public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApiLevel) {
+    return optimizationInfo.getApiReferenceLevelForDefinition(minApiLevel);
+  }
+
   public synchronized MutableFieldOptimizationInfo getMutableOptimizationInfo() {
     MutableFieldOptimizationInfo mutableInfo = optimizationInfo.toMutableOptimizationInfo();
     optimizationInfo = mutableInfo;
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
index e054ffa..c1ce2f5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.ir.optimize.info.MemberOptimizationInfo;
 import com.android.tools.r8.kotlin.KotlinMemberLevelInfo;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import java.util.function.Consumer;
 import java.util.function.Function;
 
@@ -84,6 +85,8 @@
 
   public abstract MemberOptimizationInfo<?> getOptimizationInfo();
 
+  public abstract AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApiLevel);
+
   @Override
   public final boolean equals(Object other) {
     if (other == this) {
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 2fdb279..d3af4ee 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -70,6 +70,7 @@
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.ConsumerUtils;
 import com.android.tools.r8.utils.InternalOptions;
@@ -1407,6 +1408,20 @@
     return optimizationInfo;
   }
 
+  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApiLevel) {
+    return optimizationInfo.getApiReferenceLevelForDefinition(minApiLevel);
+  }
+
+  public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApiLevel) {
+    return optimizationInfo.getApiReferenceLevelForCode(minApiLevel);
+  }
+
+  @Override
+  public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApiLevel) {
+    return getApiReferenceLevelForDefinition(minApiLevel)
+        .max(getApiReferenceLevelForCode(minApiLevel));
+  }
+
   public synchronized MutableMethodOptimizationInfo getMutableOptimizationInfo() {
     checkIfObsolete();
     MutableMethodOptimizationInfo mutableInfo = optimizationInfo.toMutableOptimizationInfo();
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 64608dc..90841e1 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -15,7 +15,6 @@
 import com.android.tools.r8.graph.GenericSignature.ClassSignature;
 import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.info.MemberOptimizationInfo;
 import com.android.tools.r8.kotlin.KotlinClassLevelInfo;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
@@ -835,9 +834,7 @@
       }
     }
     for (DexEncodedMember<?, ?> member : members()) {
-      MemberOptimizationInfo<?> optimizationInfo = member.getOptimizationInfo();
-      assert optimizationInfo.hasApiReferenceLevel();
-      computedApiLevel = optimizationInfo.getApiReferenceLevel(computedApiLevel);
+      computedApiLevel = member.getApiReferenceLevel(computedApiLevel);
       if (computedApiLevel == AndroidApiLevel.UNKNOWN) {
         return AndroidApiLevel.UNKNOWN;
       }
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 65840c5..32c9420 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
@@ -7,13 +7,16 @@
 import com.android.tools.r8.androidapi.AndroidApiReferenceLevelCache;
 import com.android.tools.r8.graph.AppView;
 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.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.optimize.info.DefaultFieldOptimizationWithMinApiInfo;
+import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationWithMinApiInfo;
 import com.android.tools.r8.ir.optimize.info.MemberOptimizationInfo;
+import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
 import com.android.tools.r8.shaking.DefaultEnqueuerUseRegistry;
 import com.android.tools.r8.utils.AndroidApiLevel;
 
@@ -31,13 +34,13 @@
 
   @Override
   public void processNewlyLiveField(ProgramField field, ProgramDefinition context) {
-    setApiLevelForMember(
+    setApiLevelForMemberDefinition(
         field.getDefinition(), computeApiLevelForReferencedTypes(field.getReference()));
   }
 
   @Override
   public void processNewlyLiveMethod(ProgramMethod method, ProgramDefinition context) {
-    setApiLevelForMember(
+    setApiLevelForMemberDefinition(
         method.getDefinition(), computeApiLevelForReferencedTypes(method.getReference()));
   }
 
@@ -51,10 +54,13 @@
           .tracedMethodApiLevelCallback
           .accept(method.getMethodReference(), registry.getMaxApiReferenceLevel());
     }
-    setApiLevelForMember(method.getDefinition(), registry.getMaxApiReferenceLevel());
+    setApiLevelForMemberDefinition(
+        method.getDefinition(), computeApiLevelForReferencedTypes(method.getReference()));
+    setApiLevelForCode(method.getDefinition(), registry.getMaxApiReferenceLevel());
   }
 
-  private void setApiLevelForMember(DexEncodedMember<?, ?> member, AndroidApiLevel apiLevel) {
+  private void setApiLevelForMemberDefinition(
+      DexEncodedMember<?, ?> member, AndroidApiLevel apiLevel) {
     // To not have mutable update information for all members that all has min api level we
     // swap the default optimization info for one with that marks the api level to be min api.
     MemberOptimizationInfo<?> optimizationInfo = member.getOptimizationInfo();
@@ -68,19 +74,29 @@
           });
     } else {
       AndroidApiLevel maxApiLevel =
-          optimizationInfo.hasApiReferenceLevel()
-              ? apiLevel.max(optimizationInfo.getApiReferenceLevel(minApiLevel))
+          optimizationInfo.hasApiReferenceLevelForDefinition()
+              ? apiLevel.max(optimizationInfo.getApiReferenceLevelForDefinition(minApiLevel))
               : apiLevel;
       member.accept(
           field -> {
-            field.getMutableOptimizationInfo().setApiReferenceLevel(maxApiLevel);
+            field.getMutableOptimizationInfo().setApiReferenceLevelForDefinition(maxApiLevel);
           },
           method -> {
-            method.getMutableOptimizationInfo().setApiReferenceLevel(maxApiLevel);
+            method.getMutableOptimizationInfo().setApiReferenceLevelForDefinition(maxApiLevel);
           });
     }
   }
 
+  private void setApiLevelForCode(DexEncodedMethod method, AndroidApiLevel apiLevel) {
+    MethodOptimizationInfo optimizationInfo = method.getOptimizationInfo();
+    assert optimizationInfo != DefaultMethodOptimizationInfo.getInstance();
+    if (!optimizationInfo.isMutableOptimizationInfo() && apiLevel == minApiLevel) {
+      assert optimizationInfo == DefaultMethodOptimizationWithMinApiInfo.getInstance();
+      return;
+    }
+    method.getMutableOptimizationInfo().setApiReferenceLevelForCode(apiLevel);
+  }
+
   private AndroidApiLevel computeApiLevelForReferencedTypes(DexMember<?, ?> member) {
     return member.computeApiLevelForReferencedTypes(appView, referenceLevelCache::lookupMax);
   }
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java
index c9788bd..28d6be7 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java
@@ -8,8 +8,6 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.code.Invoke;
-import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter.Mode;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
@@ -32,33 +30,33 @@
     converter.registerCallbackIfRequired(method);
   }
 
-  private void traceInvoke(DexMethod invokedMethod, Type invokeType, ProgramMethod context) {
-    converter.registerWrappersForLibraryInvokeIfRequired(invokedMethod, invokeType, context);
+  private void traceInvoke(DexMethod invokedMethod) {
+    converter.registerWrappersForLibraryInvokeIfRequired(invokedMethod);
   }
 
   @Override
   public void traceInvokeStatic(DexMethod invokedMethod, ProgramMethod context) {
-    this.traceInvoke(invokedMethod, Type.STATIC, context);
+    this.traceInvoke(invokedMethod);
   }
 
   @Override
   public void traceInvokeDirect(DexMethod invokedMethod, ProgramMethod context) {
-    this.traceInvoke(invokedMethod, Type.DIRECT, context);
+    this.traceInvoke(invokedMethod);
   }
 
   @Override
   public void traceInvokeInterface(DexMethod invokedMethod, ProgramMethod context) {
-    this.traceInvoke(invokedMethod, Type.INTERFACE, context);
+    this.traceInvoke(invokedMethod);
   }
 
   @Override
   public void traceInvokeSuper(DexMethod invokedMethod, ProgramMethod context) {
-    this.traceInvoke(invokedMethod, Type.SUPER, context);
+    this.traceInvoke(invokedMethod);
   }
 
   @Override
   public void traceInvokeVirtual(DexMethod invokedMethod, ProgramMethod context) {
-    this.traceInvoke(invokedMethod, Invoke.Type.VIRTUAL, context);
+    this.traceInvoke(invokedMethod);
   }
 
   public ProgramMethodSet generateCallbackMethods() {
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 514002e..9508da1 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,6 +13,8 @@
 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;
@@ -56,6 +58,7 @@
     D8CfClassDesugaringEventConsumer classDesugaringEventConsumer =
         CfClassDesugaringEventConsumer.createForD8(methodProcessor);
     converter.desugarClassesForD8(classes, classDesugaringEventConsumer, executorService);
+    converter.prepareDesugaringForD8(executorService);
 
     while (!classes.isEmpty()) {
       Set<DexType> seenNestHosts = Sets.newIdentityHashSet();
@@ -75,11 +78,6 @@
       D8CfInstructionDesugaringEventConsumer instructionDesugaringEventConsumer =
           CfInstructionDesugaringEventConsumer.createForD8(methodProcessor);
 
-      // TODO(b/191656218): Move upfront the loop and use maybe the class event consumer.
-      if (appView.options().isDesugaredLibraryCompilation()) {
-        converter.ensureWrappersForL8(instructionDesugaringEventConsumer);
-      }
-
       // Process the wave and wait for all IR processing to complete.
       methodProcessor.newWave();
       ThreadUtils.processItems(
@@ -114,6 +112,13 @@
 
       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 b6b40f8..0b3c524 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,12 +51,11 @@
 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;
@@ -95,6 +94,7 @@
 import com.android.tools.r8.ir.optimize.string.StringOptimizer;
 import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
+import com.android.tools.r8.ir.synthetic.SynthesizedCode;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.naming.IdentifierNameStringMarker;
 import com.android.tools.r8.position.MethodPosition;
@@ -226,8 +226,12 @@
       assert options.desugarState.isOn();
       this.instructionDesugaring = CfInstructionDesugaringCollection.create(appView);
       this.classDesugaring = instructionDesugaring.createClassDesugaringCollection();
-      this.interfaceMethodRewriter = null;
-      this.desugaredLibraryAPIConverter = null;
+      this.interfaceMethodRewriter =
+          options.desugaredLibraryConfiguration.getEmulateLibraryInterface().isEmpty()
+              ? null
+              : new InterfaceMethodRewriter(appView, this);
+      this.desugaredLibraryAPIConverter =
+          new DesugaredLibraryAPIConverter(appView, Mode.GENERATE_CALLBACKS_AND_WRAPPERS);
       this.covariantReturnTypeAnnotationTransformer = null;
       this.dynamicTypeOptimization = null;
       this.classInliner = null;
@@ -255,7 +259,7 @@
             : CfInstructionDesugaringCollection.create(appView);
     this.classDesugaring = instructionDesugaring.createClassDesugaringCollection();
     this.interfaceMethodRewriter =
-        options.isInterfaceMethodDesugaringEnabled() && appView.enableWholeProgramOptimizations()
+        options.isInterfaceMethodDesugaringEnabled()
             ? new InterfaceMethodRewriter(appView, this)
             : null;
     this.covariantReturnTypeAnnotationTransformer =
@@ -319,7 +323,10 @@
       this.identifierNameStringMarker = null;
       this.devirtualizer = null;
       this.typeChecker = null;
-      this.desugaredLibraryAPIConverter = null;
+      this.desugaredLibraryAPIConverter =
+          appView.rewritePrefix.isRewriting()
+              ? new DesugaredLibraryAPIConverter(appView, Mode.GENERATE_CALLBACKS_AND_WRAPPERS)
+              : null;
       this.serviceLoaderRewriter = null;
       this.methodOptimizationInfoCollector = null;
       this.enumValueOptimizer = null;
@@ -360,11 +367,9 @@
         D8NestBasedAccessDesugaring::clearNestAttributes);
   }
 
-  public void ensureWrappersForL8(
-      D8CfInstructionDesugaringEventConsumer instructionDesugaringEventConsumer) {
-    assert appView.options().isDesugaredLibraryCompilation();
-    instructionDesugaring.withDesugaredLibraryAPIConverter(
-        converter -> converter.ensureWrappersForL8(instructionDesugaringEventConsumer));
+  void postProcessDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) {
+    CfPostProcessingDesugaringCollection.create(appView, instructionDesugaring.getRetargetingInfo())
+        .postProcessingDesugaring(eventConsumer);
   }
 
   private void staticizeClasses(
@@ -389,11 +394,11 @@
     }
   }
 
-  private void runInterfaceDesugaringProcessorsForR8(
+  private void runInterfaceDesugaringProcessors(
       Flavor includeAllResources, ExecutorService executorService) throws ExecutionException {
     assert !appView.getSyntheticItems().hasPendingSyntheticClasses();
     if (interfaceMethodRewriter != null) {
-      interfaceMethodRewriter.runInterfaceDesugaringProcessorsForR8(
+      interfaceMethodRewriter.runInterfaceDesugaringProcessors(
           this, includeAllResources, executorService);
     }
   }
@@ -410,28 +415,30 @@
     workaroundAbstractMethodOnNonAbstractClassVerificationBug(
         executor, OptimizationFeedbackIgnore.getInstance());
     DexApplication application = appView.appInfo().app();
-    D8MethodProcessor methodProcessor = new D8MethodProcessor(this, executor);
-
     timing.begin("IR conversion");
 
-    convertClasses(methodProcessor, executor);
+    convertClasses(executor);
 
     reportNestDesugarDependencies();
     clearNestAttributes();
 
-    application = commitPendingSyntheticItems(appView, application);
-
-    postProcessingDesugaringForD8(methodProcessor, executor);
-
-    application = commitPendingSyntheticItems(appView, application);
+    if (appView.getSyntheticItems().hasPendingSyntheticClasses()) {
+      appView.setAppInfo(
+          new AppInfo(
+              appView.appInfo().getSyntheticItems().commit(application),
+              appView.appInfo().getMainDexInfo()));
+      application = appView.appInfo().app();
+    }
 
     // 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);
     }
     processCovariantReturnTypeAnnotations(builder);
+    generateDesugaredLibraryAPIWrappers(builder, executor);
 
     timing.end();
 
@@ -442,33 +449,8 @@
             appView.appInfo().getMainDexInfo()));
   }
 
-  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);
-    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 {
+  private void convertClasses(ExecutorService executorService) throws ExecutionException {
+    D8MethodProcessor methodProcessor = new D8MethodProcessor(this, executorService);
     ClassConverterResult classConverterResult =
         ClassConverter.create(appView, this, methodProcessor).convertClasses(executorService);
 
@@ -481,9 +463,6 @@
 
     rewriteEnclosingLambdaMethodAttributes(
         appView, classConverterResult.getForcefullyMovedLambdaMethods());
-
-    instructionDesugaring.withDesugaredLibraryAPIConverter(
-        DesugaredLibraryAPIConverter::generateTrackingWarnings);
   }
 
   public void desugarClassesForD8(
@@ -499,13 +478,27 @@
         classes, clazz -> desugarClassForD8(clazz, desugaringEventConsumer), executorService);
   }
 
-  public void desugarClassForD8(
+  private void desugarClassForD8(
       DexProgramClass clazz, D8CfClassDesugaringEventConsumer desugaringEventConsumer) {
     if (classDesugaring.needsDesugaring(clazz)) {
       classDesugaring.desugar(clazz, desugaringEventConsumer);
     }
   }
 
+  public void prepareDesugaringForD8(ExecutorService executorService) throws ExecutionException {
+    // Prepare desugaring by collecting all the synthetic methods required on program classes.
+    ProgramAdditions programAdditions = new ProgramAdditions();
+    ThreadUtils.processItems(
+        appView.appInfo().classes(),
+        clazz -> {
+          clazz.forEachProgramMethodMatching(
+              method -> method.hasCode() && method.getCode().isCfCode(),
+              method -> instructionDesugaring.prepare(method, programAdditions));
+        },
+        executorService);
+    programAdditions.apply(executorService);
+  }
+
   void convertMethods(
       DexProgramClass clazz,
       D8CfInstructionDesugaringEventConsumer desugaringEventConsumer,
@@ -578,14 +571,32 @@
     }
   }
 
-  private boolean needsIRConversion() {
+  private boolean needsIRConversion(ProgramMethod method) {
     if (appView.enableWholeProgramOptimizations()) {
       return true;
     }
     if (options.testing.forceIRForCfToCfDesugar) {
       return true;
     }
-    return !options.cfToCfDesugar;
+    if (options.isDesugaredLibraryCompilation()) {
+      return true;
+    }
+    if (!options.cfToCfDesugar) {
+      return true;
+    }
+    if (desugaredLibraryAPIConverter != null
+        && desugaredLibraryAPIConverter.shouldRegisterCallback(method)) {
+      return true;
+    }
+    if (method.getDefinition().getCode() instanceof SynthesizedCode) {
+      // SynthesizedCode needs IR to generate the code.
+      return true;
+    } else {
+      NeedsIRDesugarUseRegistry useRegistry =
+          new NeedsIRDesugarUseRegistry(method, appView, desugaredLibraryAPIConverter);
+      method.registerCodeReferences(useRegistry);
+      return useRegistry.needsDesugaring();
+    }
   }
 
   private void checkPrefixMerging(ProgramMethod method) {
@@ -786,9 +797,12 @@
 
     printPhase("Interface method desugaring");
     finalizeInterfaceMethodRewritingThroughIR(executorService);
-    runInterfaceDesugaringProcessorsForR8(IncludeAllResources, executorService);
+    runInterfaceDesugaringProcessors(IncludeAllResources, executorService);
     feedback.updateVisibleOptimizationInfo();
 
+    printPhase("Desugared library API Conversion finalization");
+    generateDesugaredLibraryAPIWrappers(builder, executorService);
+
     if (serviceLoaderRewriter != null) {
       processSynthesizedServiceLoaderMethods(
           serviceLoaderRewriter.getServiceLoadMethods(), executorService);
@@ -952,6 +966,14 @@
     removeDeadCodeAndFinalizeIR(code, OptimizationFeedbackIgnore.getInstance(), Timing.empty());
   }
 
+  private void generateDesugaredLibraryAPIWrappers(
+      DexApplication.Builder<?> builder, ExecutorService executorService)
+      throws ExecutionException {
+    if (desugaredLibraryAPIConverter != null) {
+      desugaredLibraryAPIConverter.finalizeWrappers(builder, this, executorService);
+    }
+  }
+
   private void clearDexMethodCompilationState() {
     appView.appInfo().classes().forEach(this::clearDexMethodCompilationState);
   }
@@ -1119,7 +1141,7 @@
       options.testing.hookInIrConversion.run();
     }
 
-    if (!needsIRConversion() || options.skipIR) {
+    if (!needsIRConversion(method) || options.skipIR) {
       feedback.markProcessed(method.getDefinition(), ConstraintWithTarget.NEVER);
       return Timing.empty();
     }
@@ -1477,9 +1499,10 @@
 
     previous = printMethod(code, "IR after interface method rewriting (SSA)", previous);
 
+    // This pass has to be after interfaceMethodRewriter and BackportedMethodRewriter.
     if (desugaredLibraryAPIConverter != null
-        && appView.enableWholeProgramOptimizations()
-        && methodProcessor.isPrimaryMethodProcessor()) {
+        && (!appView.enableWholeProgramOptimizations()
+            || methodProcessor.isPrimaryMethodProcessor())) {
       timing.begin("Desugar library API");
       desugaredLibraryAPIConverter.desugar(code);
       timing.end();
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java b/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
new file mode 100644
index 0000000..0d1c587
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
@@ -0,0 +1,108 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.conversion;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexCallSite;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
+
+class NeedsIRDesugarUseRegistry extends UseRegistry {
+
+  private boolean needsDesugaring = false;
+  private final ProgramMethod context;
+  private final DesugaredLibraryAPIConverter desugaredLibraryAPIConverter;
+
+  public NeedsIRDesugarUseRegistry(
+      ProgramMethod method,
+      AppView<?> appView,
+      DesugaredLibraryAPIConverter desugaredLibraryAPIConverter) {
+    super(appView.dexItemFactory());
+    this.context = method;
+    this.desugaredLibraryAPIConverter = desugaredLibraryAPIConverter;
+  }
+
+  public boolean needsDesugaring() {
+    return needsDesugaring;
+  }
+
+  @Override
+  public void registerInitClass(DexType type) {
+    if (!needsDesugaring
+        && desugaredLibraryAPIConverter != null
+        && desugaredLibraryAPIConverter.canConvert(type)) {
+      needsDesugaring = true;
+    }
+  }
+
+  @Override
+  public void registerInvokeVirtual(DexMethod method) {
+    registerDesugaredLibraryAPIConverter(method);
+  }
+
+  @Override
+  public void registerInvokeDirect(DexMethod method) {
+    registerDesugaredLibraryAPIConverter(method);
+  }
+
+  private void registerDesugaredLibraryAPIConverter(DexMethod method) {
+    if (!needsDesugaring) {
+      needsDesugaring =
+          desugaredLibraryAPIConverter != null
+              && desugaredLibraryAPIConverter.shouldRewriteInvoke(method);
+    }
+  }
+
+  @Override
+  public void registerInvokeStatic(DexMethod method) {
+    registerDesugaredLibraryAPIConverter(method);
+  }
+
+  @Override
+  public void registerInvokeInterface(DexMethod method) {
+    registerDesugaredLibraryAPIConverter(method);
+  }
+
+  @Override
+  public void registerInvokeStatic(DexMethod method, boolean itf) {
+    registerInvokeStatic(method);
+  }
+
+  @Override
+  public void registerCallSite(DexCallSite callSite) {
+    super.registerCallSite(callSite);
+    needsDesugaring = true;
+  }
+
+  @Override
+  public void registerInvokeSuper(DexMethod method) {
+    registerDesugaredLibraryAPIConverter(method);
+  }
+
+  @Override
+  public void registerInstanceFieldRead(DexField field) {}
+
+  @Override
+  public void registerInstanceFieldWrite(DexField field) {}
+
+  @Override
+  public void registerNewInstance(DexType type) {}
+
+  @Override
+  public void registerStaticFieldRead(DexField field) {}
+
+  @Override
+  public void registerStaticFieldWrite(DexField field) {}
+
+  @Override
+  public void registerTypeReference(DexType type) {}
+
+  @Override
+  public void registerInstanceOf(DexType type) {}
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
index 9d7b629..513a9d5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
@@ -13,11 +13,23 @@
 /** Interface for desugaring a single class-file instruction. */
 public interface CfInstructionDesugaring {
 
+  // TODO(193004879): Merge the scan and prepare methods.
   default void scan(ProgramMethod method, CfInstructionDesugaringEventConsumer eventConsumer) {
     // Default scan is to do nothing.
   }
 
   /**
+   * Prepare step which is called on all classes scheduled for desugaring before the actual
+   * instruction level desugaring is preformed. This allows the desugaring to prepare and provide
+   * additional methods for program classes which will be needed for desugaring. During desugaring
+   * synthetic items can be added and the instruction stream can be altered, but program methods
+   * cannot be added.
+   */
+  default void prepare(ProgramMethod method, ProgramAdditions programAdditions) {
+    // Default prepare is to do nothing.
+  }
+
+  /**
    * Given an instruction, returns the list of instructions that the instruction should be desugared
    * to. If no desugaring is needed, {@code null} should be returned (for efficiency).
    */
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 cd9a9ec..6efa25b 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
@@ -7,13 +7,9 @@
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
 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;
-import java.util.function.Consumer;
 
 /**
  * Abstracts a collection of low-level desugarings (i.e., mappings from class-file instructions to
@@ -39,6 +35,8 @@
     return EmptyCfInstructionDesugaringCollection.getInstance();
   }
 
+  public abstract void prepare(ProgramMethod method, ProgramAdditions programAdditions);
+
   public abstract void scan(
       ProgramMethod method, CfInstructionDesugaringEventConsumer eventConsumer);
 
@@ -60,11 +58,5 @@
   public abstract <T extends Throwable> void withD8NestBasedAccessDesugaring(
       ThrowingConsumer<D8NestBasedAccessDesugaring, T> consumer) throws T;
 
-  public abstract InterfaceMethodProcessorFacade getInterfaceMethodPostProcessingDesugaring(
-      Flavor flavor);
-
   public abstract RetargetingInfo getRetargetingInfo();
-
-  public abstract void withDesugaredLibraryAPIConverter(
-      Consumer<DesugaredLibraryAPIConverter> consumer);
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
index cb9aeb9..d497332 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
@@ -15,7 +15,6 @@
 import com.android.tools.r8.ir.conversion.ClassConverterResult;
 import com.android.tools.r8.ir.conversion.D8MethodProcessor;
 import com.android.tools.r8.ir.desugar.backports.BackportedMethodDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverterEventConsumer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterInstructionEventConsumer;
 import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialBridgeInfo;
 import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialToSelfDesugaringEventConsumer;
@@ -26,7 +25,6 @@
 import com.android.tools.r8.ir.desugar.records.RecordDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.twr.TwrCloseResourceDesugaringEventConsumer;
 import com.android.tools.r8.shaking.Enqueuer.SyntheticAdditions;
-import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -35,7 +33,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
@@ -51,8 +48,7 @@
         RecordDesugaringEventConsumer,
         TwrCloseResourceDesugaringEventConsumer,
         InterfaceMethodDesugaringEventConsumer,
-        DesugaredLibraryRetargeterInstructionEventConsumer,
-        DesugaredLibraryAPIConverterEventConsumer {
+        DesugaredLibraryRetargeterInstructionEventConsumer {
 
   public static D8CfInstructionDesugaringEventConsumer createForD8(
       D8MethodProcessor methodProcessor) {
@@ -72,26 +68,6 @@
     return new CfInstructionDesugaringEventConsumer() {
 
       @Override
-      public void acceptWrapperProgramClass(DexProgramClass clazz) {
-        assert false;
-      }
-
-      @Override
-      public void acceptWrapperClasspathClass(DexClasspathClass clazz) {
-        assert false;
-      }
-
-      @Override
-      public void acceptAPIConversion(ProgramMethod method) {
-        assert false;
-      }
-
-      @Override
-      public void acceptSuperAPIConversion(ProgramMethod method) {
-        assert false;
-      }
-
-      @Override
       public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
         assert false;
       }
@@ -171,8 +147,6 @@
 
     private final Map<DexReference, InvokeSpecialBridgeInfo> pendingInvokeSpecialBridges =
         new LinkedHashMap<>();
-    private final Map<DexProgramClass, SortedProgramMethodSet> pendingSuperAPIConversions =
-        new ConcurrentHashMap<>();
     private final List<LambdaClass> synthesizedLambdaClasses = new ArrayList<>();
 
     private D8CfInstructionDesugaringEventConsumer(D8MethodProcessor methodProcessor) {
@@ -226,17 +200,17 @@
 
     @Override
     public void acceptNestFieldGetBridge(ProgramField target, ProgramMethod bridge) {
-      methodProcessor.scheduleDesugaredMethodForProcessing(bridge);
+      assert false;
     }
 
     @Override
     public void acceptNestFieldPutBridge(ProgramField target, ProgramMethod bridge) {
-      methodProcessor.scheduleDesugaredMethodForProcessing(bridge);
+      assert false;
     }
 
     @Override
     public void acceptNestMethodBridge(ProgramMethod target, ProgramMethod bridge) {
-      methodProcessor.scheduleDesugaredMethodForProcessing(bridge);
+      assert false;
     }
 
     @Override
@@ -255,48 +229,14 @@
       methodProcessor.scheduleDesugaredMethodForProcessing(method);
     }
 
-    @Override
-    public void acceptWrapperProgramClass(DexProgramClass clazz) {
-      methodProcessor.scheduleDesugaredMethodsForProcessing(clazz.programMethods());
-    }
-
-    @Override
-    public void acceptWrapperClasspathClass(DexClasspathClass clazz) {
-      // Intentionally empty.
-    }
-
-    @Override
-    public void acceptAPIConversion(ProgramMethod method) {
-      methodProcessor.scheduleDesugaredMethodForProcessing(method);
-    }
-
-    @Override
-    public void acceptSuperAPIConversion(ProgramMethod method) {
-      SortedProgramMethodSet superAPIConversions =
-          pendingSuperAPIConversions.computeIfAbsent(
-              method.getHolder(), ignored -> SortedProgramMethodSet.createConcurrent());
-      superAPIConversions.add(method);
-    }
-
     public List<ProgramMethod> finalizeDesugaring(
         AppView<?> appView, ClassConverterResult.Builder classConverterResultBuilder) {
       List<ProgramMethod> needsProcessing = new ArrayList<>();
       finalizeInvokeSpecialDesugaring(appView, needsProcessing::add);
       finalizeLambdaDesugaring(classConverterResultBuilder, needsProcessing::add);
-      finalizeSuperAPIConversionDesugaring(needsProcessing::add);
       return needsProcessing;
     }
 
-    private void finalizeSuperAPIConversionDesugaring(Consumer<ProgramMethod> needsProcessing) {
-      for (SortedProgramMethodSet superAPIConversions : pendingSuperAPIConversions.values()) {
-        for (ProgramMethod superAPIConversion : superAPIConversions) {
-          superAPIConversion.getHolder().addDirectMethod(superAPIConversion.getDefinition());
-          needsProcessing.accept(superAPIConversion);
-        }
-      }
-      pendingSuperAPIConversions.clear();
-    }
-
     private void finalizeInvokeSpecialDesugaring(
         AppView<?> appView, Consumer<ProgramMethod> needsProcessing) {
       // Fixup the code of the new private methods have that been synthesized.
@@ -408,30 +348,6 @@
     }
 
     @Override
-    public void acceptWrapperProgramClass(DexProgramClass clazz) {
-      // TODO(b/189912077): There should be nothing to do.
-      assert false;
-    }
-
-    @Override
-    public void acceptWrapperClasspathClass(DexClasspathClass clazz) {
-      // TODO(b/189912077): Should be added to live non program types.
-      assert false;
-    }
-
-    @Override
-    public void acceptAPIConversion(ProgramMethod method) {
-      // TODO(b/189912077): There should be nothing to do.
-      assert false;
-    }
-
-    @Override
-    public void acceptSuperAPIConversion(ProgramMethod method) {
-      // TODO(b/189912077): Manage pending conversions.
-      assert false;
-    }
-
-    @Override
     public void acceptBackportedMethod(ProgramMethod backportedMethod, ProgramMethod context) {
       // Intentionally empty. The backported method will be hit by the tracing in R8 as if it was
       // present in the input code, and thus nothing needs to be done.
@@ -456,20 +372,17 @@
 
     @Override
     public void acceptNestFieldGetBridge(ProgramField target, ProgramMethod bridge) {
-      // Intentionally empty. These bridges will be hit by the tracing in R8 as if they were present
-      // in the input code, and thus nothing needs to be done.
+      assert false;
     }
 
     @Override
     public void acceptNestFieldPutBridge(ProgramField target, ProgramMethod bridge) {
-      // Intentionally empty. These bridges will be hit by the tracing in R8 as if they were present
-      // in the input code, and thus nothing needs to be done.
+      assert false;
     }
 
     @Override
     public void acceptNestMethodBridge(ProgramMethod target, ProgramMethod bridge) {
-      // Intentionally empty. These bridges will be hit by the tracing in R8 as if they were present
-      // in the input code, and thus nothing needs to be done.
+      assert false;
     }
 
     @Override
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 38a0413..2a2de5f 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,12 +3,7 @@
 // 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, ExecutorService executorService)
-      throws ExecutionException;
+  void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer);
 }
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 367e0ca..f659ad8 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
@@ -4,24 +4,17 @@
 package com.android.tools.r8.ir.desugar;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterPostProcessor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
-import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
 
 public abstract class CfPostProcessingDesugaringCollection {
 
   public static CfPostProcessingDesugaringCollection create(
-      AppView<?> appView,
-      InterfaceMethodProcessorFacade interfaceMethodProcessorFacade,
-      RetargetingInfo retargetingInfo) {
+      AppView<?> appView, RetargetingInfo retargetingInfo) {
     if (appView.options().desugarState.isOn()) {
-      return NonEmptyCfPostProcessingDesugaringCollection.create(
-          appView, interfaceMethodProcessorFacade, retargetingInfo);
+      return NonEmptyCfPostProcessingDesugaringCollection.create(appView, retargetingInfo);
     }
     return empty();
   }
@@ -31,8 +24,7 @@
   }
 
   public abstract void postProcessingDesugaring(
-      CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
-      throws ExecutionException;
+      CfPostProcessingDesugaringEventConsumer eventConsumer);
 
   public static class NonEmptyCfPostProcessingDesugaringCollection
       extends CfPostProcessingDesugaringCollection {
@@ -45,37 +37,19 @@
     }
 
     public static CfPostProcessingDesugaringCollection create(
-        AppView<?> appView,
-        InterfaceMethodProcessorFacade interfaceMethodProcessorFacade,
-        RetargetingInfo retargetingInfo) {
-      ArrayList<CfPostProcessingDesugaring> desugarings = new ArrayList<>();
-      if (!appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) {
-        desugarings.add(new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo));
-      }
-      if (interfaceMethodProcessorFacade != null) {
-        desugarings.add(interfaceMethodProcessorFacade);
-      }
-      DesugaredLibraryAPIConverter desugaredLibraryAPIConverter =
-          appView.rewritePrefix.isRewriting() && !appView.enableWholeProgramOptimizations()
-              ? new DesugaredLibraryAPIConverter(appView, null)
-              : null;
-      // At this point the desugaredLibraryAPIConverter is required to be last to generate
-      // call-backs on the forwarding methods.
-      if (desugaredLibraryAPIConverter != null) {
-        desugarings.add(desugaredLibraryAPIConverter);
-      }
-      if (desugarings.isEmpty()) {
+        AppView<?> appView, RetargetingInfo retargetingInfo) {
+      if (appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) {
         return empty();
       }
-      return new NonEmptyCfPostProcessingDesugaringCollection(desugarings);
+      return new NonEmptyCfPostProcessingDesugaringCollection(
+          Collections.singletonList(
+              new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo)));
     }
 
     @Override
-    public void postProcessingDesugaring(
-        CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
-        throws ExecutionException {
+    public void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) {
       for (CfPostProcessingDesugaring desugaring : desugarings) {
-        desugaring.postProcessingDesugaring(eventConsumer, executorService);
+        desugaring.postProcessingDesugaring(eventConsumer);
       }
     }
   }
@@ -93,9 +67,7 @@
     }
 
     @Override
-    public void postProcessingDesugaring(
-        CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
-        throws ExecutionException {
+    public void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) {
       // 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 f5af1f1..dc67ee9 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
@@ -10,12 +10,8 @@
 import com.android.tools.r8.graph.ProgramMethod;
 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.DesugaredLibraryAPIConverterEventConsumer.DesugaredLibraryAPIConverterPostProcessingEventConsumer;
 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
@@ -23,13 +19,16 @@
  * explicit calls must be done here.
  */
 public abstract class CfPostProcessingDesugaringEventConsumer
-    implements DesugaredLibraryRetargeterPostProcessingEventConsumer,
-        InterfaceProcessingDesugaringEventConsumer,
-        DesugaredLibraryAPIConverterPostProcessingEventConsumer {
+    implements DesugaredLibraryRetargeterPostProcessingEventConsumer {
+  protected DesugaredLibraryAPIConverter desugaredLibraryAPIConverter;
+
+  protected CfPostProcessingDesugaringEventConsumer(AppView<?> appView) {
+    this.desugaredLibraryAPIConverter = new DesugaredLibraryAPIConverter(appView, null);
+  }
 
   public static D8CfPostProcessingDesugaringEventConsumer createForD8(
-      D8MethodProcessor methodProcessor) {
-    return new D8CfPostProcessingDesugaringEventConsumer(methodProcessor);
+      D8MethodProcessor methodProcessor, AppView<?> appView) {
+    return new D8CfPostProcessingDesugaringEventConsumer(methodProcessor, appView);
   }
 
   public static R8PostProcessingDesugaringEventConsumer createForR8(
@@ -37,22 +36,23 @@
     return new R8PostProcessingDesugaringEventConsumer(appView, additions);
   }
 
-  public abstract void finalizeDesugaring() throws ExecutionException;
+  public void finalizeDesugaring() {
+    desugaredLibraryAPIConverter.generateTrackingWarnings();
+  }
 
   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) {
+    private D8CfPostProcessingDesugaringEventConsumer(
+        D8MethodProcessor methodProcessor, AppView<?> appView) {
+      super(appView);
       this.methodProcessor = methodProcessor;
     }
 
     @Override
     public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
-      methodsToReprocess.addAll(clazz.programMethods());
+      methodProcessor.scheduleDesugaredMethodsForProcessing(clazz.programMethods());
     }
 
     @Override
@@ -67,30 +67,9 @@
 
     @Override
     public void acceptForwardingMethod(ProgramMethod 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 acceptAPIConversionCallback(ProgramMethod method) {
-      methodsToReprocess.add(method);
-    }
-
-    @Override
-    public void finalizeDesugaring() throws ExecutionException {
-      assert methodProcessor.verifyNoPendingMethodProcessing();
-      methodProcessor.newWave();
-      methodProcessor.scheduleDesugaredMethodsForProcessing(methodsToReprocess);
-      methodProcessor.awaitMethodProcessing();
+      methodProcessor.scheduleDesugaredMethodForProcessing(method);
+      // TODO(b/189912077): Uncomment when API conversion is performed cf to cf in D8.
+      // desugaredLibraryAPIConverter.generateCallbackIfRequired(method);
     }
   }
 
@@ -98,22 +77,13 @@
       extends CfPostProcessingDesugaringEventConsumer {
     private final SyntheticAdditions additions;
 
-    // The desugaredLibraryAPIConverter is required here because call-backs need to be generated
-    // once forwarding methods are generated. We should be able to remove it once the interface
-    // method desugaring and the API converter are moved cf to cf in R8.
-    private final DesugaredLibraryAPIConverter desugaredLibraryAPIConverter;
-
-    R8PostProcessingDesugaringEventConsumer(AppView<?> appView, SyntheticAdditions additions) {
-      this.desugaredLibraryAPIConverter = new DesugaredLibraryAPIConverter(appView, null);
+    protected R8PostProcessingDesugaringEventConsumer(
+        AppView<?> appView, SyntheticAdditions additions) {
+      super(appView);
       this.additions = additions;
     }
 
     @Override
-    public void finalizeDesugaring() throws ExecutionException {
-      desugaredLibraryAPIConverter.generateTrackingWarnings();
-    }
-
-    @Override
     public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
       additions.addLiveMethods(clazz.programMethods());
     }
@@ -131,22 +101,10 @@
     @Override
     public void acceptForwardingMethod(ProgramMethod method) {
       additions.addLiveMethod(method);
-      desugaredLibraryAPIConverter.generateCallbackIfRequired(method, this);
-    }
-
-    @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";
-    }
-
-    @Override
-    public void acceptAPIConversionCallback(ProgramMethod method) {
-      additions.addLiveMethod(method);
+      ProgramMethod callback = desugaredLibraryAPIConverter.generateCallbackIfRequired(method);
+      if (callback != null) {
+        additions.addLiveMethod(callback);
+      }
     }
   }
 }
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 c78f6db..61c9617 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
@@ -7,13 +7,9 @@
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.CfClassDesugaringCollection.EmptyCfClassDesugaringCollection;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
 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;
-import java.util.function.Consumer;
 
 public class EmptyCfInstructionDesugaringCollection extends CfInstructionDesugaringCollection {
 
@@ -28,6 +24,11 @@
   }
 
   @Override
+  public void prepare(ProgramMethod method, ProgramAdditions additionalProgramMethods) {
+    // Intentionally empty.
+  }
+
+  @Override
   public void scan(ProgramMethod method, CfInstructionDesugaringEventConsumer eventConsumer) {
     // Intentionally empty.
   }
@@ -62,17 +63,7 @@
   }
 
   @Override
-  public InterfaceMethodProcessorFacade getInterfaceMethodPostProcessingDesugaring(Flavor flavor) {
-    return null;
-  }
-
-  @Override
   public RetargetingInfo getRetargetingInfo() {
     return null;
   }
-
-  @Override
-  public void withDesugaredLibraryAPIConverter(Consumer<DesugaredLibraryAPIConverter> consumer) {
-    // Intentionally empty.
-  }
 }
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 b1ea3a0..8ddd45c 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
@@ -14,13 +14,10 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.CfClassDesugaringCollection.EmptyCfClassDesugaringCollection;
 import com.android.tools.r8.ir.desugar.CfClassDesugaringCollection.NonEmptyCfClassDesugaringCollection;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
 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;
@@ -36,7 +33,6 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
-import java.util.function.Consumer;
 
 public class NonEmptyCfInstructionDesugaringCollection extends CfInstructionDesugaringCollection {
 
@@ -46,8 +42,6 @@
   private final NestBasedAccessDesugaring nestBasedAccessDesugaring;
   private final RecordRewriter recordRewriter;
   private final DesugaredLibraryRetargeter desugaredLibraryRetargeter;
-  private final InterfaceMethodRewriter interfaceMethodRewriter;
-  private final DesugaredLibraryAPIConverter desugaredLibraryAPIConverter;
 
   NonEmptyCfInstructionDesugaringCollection(AppView<?> appView) {
     this.appView = appView;
@@ -55,8 +49,6 @@
       this.nestBasedAccessDesugaring = null;
       this.recordRewriter = null;
       this.desugaredLibraryRetargeter = null;
-      this.interfaceMethodRewriter = null;
-      this.desugaredLibraryAPIConverter = null;
       return;
     }
     this.nestBasedAccessDesugaring = NestBasedAccessDesugaring.create(appView);
@@ -78,23 +70,9 @@
     // TODO(b/183998768): Enable interface method rewriter cf to cf also in R8.
     if (appView.options().isInterfaceMethodDesugaringEnabled()
         && !appView.enableWholeProgramOptimizations()) {
-      interfaceMethodRewriter =
+      desugarings.add(
           new InterfaceMethodRewriter(
-              appView, backportedMethodRewriter, desugaredLibraryRetargeter);
-      desugarings.add(interfaceMethodRewriter);
-    } else {
-      interfaceMethodRewriter = null;
-    }
-    desugaredLibraryAPIConverter =
-        appView.rewritePrefix.isRewriting() && !appView.enableWholeProgramOptimizations()
-            ? new DesugaredLibraryAPIConverter(
-                appView,
-                interfaceMethodRewriter,
-                desugaredLibraryRetargeter,
-                backportedMethodRewriter)
-            : null;
-    if (desugaredLibraryAPIConverter != null) {
-      desugarings.add(desugaredLibraryAPIConverter);
+              appView, backportedMethodRewriter, desugaredLibraryRetargeter));
     }
     desugarings.add(new LambdaInstructionDesugaring(appView));
     desugarings.add(new InvokeSpecialToSelfDesugaring(appView));
@@ -149,6 +127,12 @@
   }
 
   @Override
+  public void prepare(ProgramMethod method, ProgramAdditions programAdditions) {
+    ensureCfCode(method);
+    desugarings.forEach(d -> d.prepare(method, programAdditions));
+  }
+
+  @Override
   public void scan(ProgramMethod method, CfInstructionDesugaringEventConsumer eventConsumer) {
     ensureCfCode(method);
     desugarings.forEach(d -> d.scan(method, eventConsumer));
@@ -328,24 +312,10 @@
   }
 
   @Override
-  public InterfaceMethodProcessorFacade getInterfaceMethodPostProcessingDesugaring(Flavor flavor) {
-    return interfaceMethodRewriter != null
-        ? interfaceMethodRewriter.getPostProcessingDesugaring(flavor)
-        : null;
-  }
-
-  @Override
   public RetargetingInfo getRetargetingInfo() {
     if (desugaredLibraryRetargeter != null) {
       return desugaredLibraryRetargeter.getRetargetingInfo();
     }
     return null;
   }
-
-  @Override
-  public void withDesugaredLibraryAPIConverter(Consumer<DesugaredLibraryAPIConverter> consumer) {
-    if (desugaredLibraryAPIConverter != null) {
-      consumer.accept(desugaredLibraryAPIConverter);
-    }
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ProgramAdditions.java b/src/main/java/com/android/tools/r8/ir/desugar/ProgramAdditions.java
new file mode 100644
index 0000000..cf57453
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ProgramAdditions.java
@@ -0,0 +1,53 @@
+// 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;
+
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMember;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.utils.ThreadUtils;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.function.BiConsumer;
+import java.util.function.Supplier;
+
+public class ProgramAdditions implements BiConsumer<DexMember<?, ?>, Supplier<ProgramMethod>> {
+  private final Set<DexReference> added = Sets.newConcurrentHashSet();
+  private final Map<DexProgramClass, List<DexEncodedMethod>> additions = new ConcurrentHashMap<>();
+
+  @Override
+  public synchronized void accept(
+      DexMember<?, ?> reference, Supplier<ProgramMethod> programMethodSupplier) {
+    if (added.add(reference)) {
+      ProgramMethod method = programMethodSupplier.get();
+      List<DexEncodedMethod> methods =
+          additions.computeIfAbsent(method.getHolder(), k -> new ArrayList<>());
+      synchronized (methods) {
+        assert !methods.contains(method.getDefinition());
+        assert method.getHolder().lookupProgramMethod(method.getReference()) == null;
+        methods.add(method.getDefinition());
+      }
+    }
+  }
+
+  public void apply(ExecutorService executorService) throws ExecutionException {
+    ThreadUtils.processMap(
+        additions,
+        (clazz, methods) -> {
+          methods.sort(Comparator.comparing(DexEncodedMethod::getReference));
+          clazz.getMethodCollection().addDirectMethods(methods);
+        },
+        executorService);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
index 3fb9030..b50ac86 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
@@ -4,13 +4,10 @@
 
 package com.android.tools.r8.ir.desugar.desugaredlibrary;
 
-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.CfCode;
 import com.android.tools.r8.graph.DebugLocalInfo;
-import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexClasspathClass;
@@ -20,9 +17,6 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
-import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -31,22 +25,11 @@
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.Invoke;
-import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.InvokeStatic;
 import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
-import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
-import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring;
-import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.FreshLocalProvider;
-import com.android.tools.r8.ir.desugar.LocalStackAllocator;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverterEventConsumer.DesugaredLibraryAPIConverterPostProcessingEventConsumer;
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
-import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConversionCfCodeProvider;
+import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterWrapperCfCodeProvider;
-import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.OptionalBool;
@@ -55,17 +38,15 @@
 import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.function.Consumer;
-import org.jetbrains.annotations.Nullable;
-import org.objectweb.asm.Opcodes;
 
 // I convert library calls with desugared parameters/return values so they can work normally.
 // In the JSON of the desugared library, one can specify conversions between desugared and
@@ -81,31 +62,22 @@
 // DesugarType is only a rewritten type (generated through rewriting of type).
 // The type, from the library, may either be rewritten to the desugarType,
 // or be a rewritten type (generated through rewriting of vivifiedType).
-public class DesugaredLibraryAPIConverter
-    implements CfInstructionDesugaring, CfPostProcessingDesugaring {
+public class DesugaredLibraryAPIConverter {
 
   static final String VIVIFIED_PREFIX = "$-vivified-$.";
   public static final String DESCRIPTOR_VIVIFIED_PREFIX = "L$-vivified-$/";
-  private static final String SUPER_CONVERSION_METHOD_PREFIX = "api$super$conversion$";
 
   private final AppView<?> appView;
   private final DexItemFactory factory;
   // For debugging only, allows to assert that synthesized code in R8 have been synthesized in the
   // Enqueuer and not during IR processing.
   private final Mode mode;
-  // This is used to filter out double desugaring on backported methods.
-  private final BackportedMethodRewriter backportedMethodRewriter;
-  private final InterfaceMethodRewriter interfaceMethodRewriter;
-  private final DesugaredLibraryRetargeter retargeter;
-
   private final DesugaredLibraryWrapperSynthesizer wrapperSynthesizor;
   private final Map<DexClass, Set<DexEncodedMethod>> callBackMethods = new IdentityHashMap<>();
   private final Map<DexProgramClass, List<DexEncodedMethod>> pendingCallBackMethods =
       new IdentityHashMap<>();
   private final Set<DexMethod> trackedCallBackAPIs;
   private final Set<DexMethod> trackedAPIs;
-  private final MethodAccessFlags superAPIConversionMethodAccessFlags =
-      MethodAccessFlags.createPublicStaticSynthetic();
 
   public enum Mode {
     GENERATE_CALLBACKS_AND_WRAPPERS,
@@ -113,29 +85,9 @@
   }
 
   public DesugaredLibraryAPIConverter(AppView<?> appView, Mode mode) {
-    this(appView, mode, null, null, null);
-  }
-
-  public DesugaredLibraryAPIConverter(
-      AppView<?> appView,
-      InterfaceMethodRewriter interfaceMethodRewriter,
-      DesugaredLibraryRetargeter retargeter,
-      BackportedMethodRewriter backportedMethodRewriter) {
-    this(appView, null, interfaceMethodRewriter, retargeter, backportedMethodRewriter);
-  }
-
-  private DesugaredLibraryAPIConverter(
-      AppView<?> appView,
-      Mode mode,
-      InterfaceMethodRewriter interfaceMethodRewriter,
-      DesugaredLibraryRetargeter retargeter,
-      BackportedMethodRewriter backportedMethodRewriter) {
     this.appView = appView;
     this.factory = appView.dexItemFactory();
     this.mode = mode;
-    this.interfaceMethodRewriter = interfaceMethodRewriter;
-    this.retargeter = retargeter;
-    this.backportedMethodRewriter = backportedMethodRewriter;
     this.wrapperSynthesizor = new DesugaredLibraryWrapperSynthesizer(appView, this);
     if (appView.options().testing.trackDesugaredAPIConversions) {
       trackedCallBackAPIs = Sets.newConcurrentHashSet();
@@ -146,95 +98,6 @@
     }
   }
 
-  // TODO(b/191656218): Consider parallelizing post processing across classes instead of per
-  // implementor
-  // method.
-  @Override
-  public void postProcessingDesugaring(
-      CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService) {
-    assert noPendingWrappersOrConversions();
-    for (DexProgramClass clazz : appView.appInfo().classes()) {
-      if (!appView.isAlreadyLibraryDesugared(clazz)) {
-        ArrayList<DexEncodedMethod> callbacks = new ArrayList<>();
-        for (ProgramMethod virtualProgramMethod : clazz.virtualProgramMethods()) {
-          if (shouldRegisterCallback(virtualProgramMethod)) {
-            if (trackedCallBackAPIs != null) {
-              trackedCallBackAPIs.add(virtualProgramMethod.getReference());
-            }
-            ProgramMethod callback =
-                generateCallbackMethod(
-                    virtualProgramMethod.getDefinition(),
-                    virtualProgramMethod.getHolder(),
-                    eventConsumer);
-            callbacks.add(callback.getDefinition());
-          }
-        }
-        if (!callbacks.isEmpty()) {
-          clazz.addVirtualMethods(callbacks);
-        }
-      }
-    }
-    assert noPendingWrappersOrConversions();
-    generateTrackingWarnings();
-  }
-
-  private boolean noPendingWrappersOrConversions() {
-    for (DexProgramClass pendingSyntheticClass :
-        appView.getSyntheticItems().getPendingSyntheticClasses()) {
-      assert !isAPIConversionSyntheticType(pendingSyntheticClass.type);
-    }
-    return true;
-  }
-
-  @Override
-  public Collection<CfInstruction> desugarInstruction(
-      CfInstruction instruction,
-      FreshLocalProvider freshLocalProvider,
-      LocalStackAllocator localStackAllocator,
-      CfInstructionDesugaringEventConsumer eventConsumer,
-      ProgramMethod context,
-      MethodProcessingContext methodProcessingContext,
-      DexItemFactory dexItemFactory) {
-    assert !appView.enableWholeProgramOptimizations();
-    if (needsDesugaring(instruction, context)) {
-      assert instruction.isInvoke();
-      return Collections.singletonList(
-          rewriteLibraryInvoke(
-              instruction.asInvoke(), methodProcessingContext, eventConsumer, context));
-    }
-    return null;
-  }
-
-  @Override
-  public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
-    if (!instruction.isInvoke()) {
-      return false;
-    }
-    if (skipDesugaring(context)) {
-      return false;
-    }
-    CfInvoke invoke = instruction.asInvoke();
-    return shouldRewriteInvoke(
-        invoke.getMethod(), invoke.getInvokeType(context), invoke.isInterface(), context);
-  }
-
-  // We should not generate conversion for Wrappers and for conversion methods.
-  private boolean skipDesugaring(ProgramMethod method) {
-    return isAPIConversionSyntheticType(method.getHolderType())
-        || isSuperAPIConversionMethod(method);
-  }
-
-  private boolean isSuperAPIConversionMethod(ProgramMethod method) {
-    return method.getDefinition().isD8R8Synthesized()
-        && method.getAccessFlags().equals(superAPIConversionMethodAccessFlags)
-        && method.getName().toString().startsWith(SUPER_CONVERSION_METHOD_PREFIX);
-  }
-
-  private boolean isAPIConversionSyntheticType(DexType type) {
-    return wrapperSynthesizor.isSyntheticWrapper(type)
-        || appView.getSyntheticItems().isSyntheticOfKind(type, SyntheticKind.API_CONVERSION);
-  }
-
   public static boolean isVivifiedType(DexType type) {
     return type.descriptor.toString().startsWith(DESCRIPTOR_VIVIFIED_PREFIX);
   }
@@ -245,8 +108,6 @@
 
   public void desugar(IRCode code) {
 
-    assert appView.enableWholeProgramOptimizations();
-
     if (wrapperSynthesizor.isSyntheticWrapper(code.method().getHolderType())) {
       return;
     }
@@ -267,34 +128,26 @@
           continue;
         }
         InvokeMethod invokeMethod = instruction.asInvokeMethod();
-        DexMethod invokedMethod = invokeMethod.getInvokedMethod();
+        DexMethod invokedMethod;
+        if (invokeMethod.isInvokeSuper()) {
+          DexClassAndMethod result =
+              appView
+                  .appInfoForDesugaring()
+                  .lookupSuperTarget(invokeMethod.getInvokedMethod(), code.context());
+          invokedMethod = result != null ? result.getReference() : null;
+        } else {
+          // TODO(b/192439456): Make a test to prove resolution is needed here and fix it.
+          invokedMethod = invokeMethod.getInvokedMethod();
+        }
         // Library methods do not understand desugared types, hence desugared types have to be
         // converted around non desugared library calls for the invoke to resolve.
-        if (invokedMethod != null
-            && shouldRewriteInvoke(
-                invokedMethod,
-                invokeMethod.getType(),
-                invokeMethod.getInterfaceBit(),
-                code.context())) {
+        if (invokedMethod != null && shouldRewriteInvoke(invokedMethod)) {
           rewriteLibraryInvoke(code, invokeMethod, iterator, blockIterator);
         }
       }
     }
   }
 
-  @Nullable
-  private DexMethod getMethodForDesugaring(
-      DexMethod invokedMethod, boolean isInvokeSuper, ProgramMethod context) {
-    if (isInvokeSuper) {
-      // TODO(b/191656218): Use lookupInvokeSpecial instead when this is all to Cf.
-      DexClassAndMethod result =
-          appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
-      return result != null ? result.getReference() : null;
-    }
-    // TODO(b/192439456): Make a test to prove resolution is needed here and fix it.
-    return invokedMethod;
-  }
-
   private boolean validateCallbackWasGeneratedInEnqueuer(ProgramMethod method) {
     if (!shouldRegisterCallback(method)) {
       return true;
@@ -304,17 +157,7 @@
     return true;
   }
 
-  private boolean shouldRewriteInvoke(
-      DexMethod unresolvedInvokedMethod,
-      Type invokeType,
-      Boolean isInterface,
-      ProgramMethod context) {
-    DexMethod invokedMethod =
-        getMethodForDesugaring(unresolvedInvokedMethod, invokeType == Type.SUPER, context);
-    if (invokedMethod == null) {
-      // Implies a resolution/look-up failure, we do not convert to keep the runtime error.
-      return false;
-    }
+  public boolean shouldRewriteInvoke(DexMethod invokedMethod) {
     if (appView.rewritePrefix.hasRewrittenType(invokedMethod.holder, appView)
         || invokedMethod.holder.isArrayType()) {
       return false;
@@ -323,19 +166,6 @@
     if (dexClass == null || !dexClass.isLibraryClass()) {
       return false;
     }
-    if (interfaceMethodRewriter != null
-        && interfaceMethodRewriter.needsRewriting(invokedMethod, invokeType, context)) {
-      return false;
-    }
-    assert retargeter == null || isInterface != null;
-    if (retargeter != null
-        && retargeter.hasNewInvokeTarget(invokedMethod, false, invokeType == Type.SUPER, context)) {
-      return false;
-    }
-    if (backportedMethodRewriter != null
-        && backportedMethodRewriter.methodIsBackport(invokedMethod)) {
-      return false;
-    }
     return appView.rewritePrefix.hasRewrittenTypeInSignature(invokedMethod.proto, appView);
   }
 
@@ -345,18 +175,16 @@
     }
   }
 
-  public void generateCallbackIfRequired(
-      ProgramMethod method, DesugaredLibraryAPIConverterPostProcessingEventConsumer eventConsumer) {
+  public ProgramMethod generateCallbackIfRequired(ProgramMethod method) {
     if (!shouldRegisterCallback(method)) {
-      return;
+      return null;
     }
     if (trackedCallBackAPIs != null) {
       trackedCallBackAPIs.add(method.getReference());
     }
-    ProgramMethod callback =
-        generateCallbackMethod(method.getDefinition(), method.getHolder(), eventConsumer);
-    callback.getHolder().addVirtualMethod(callback.getDefinition());
-    assert noPendingWrappersOrConversions();
+    ProgramMethod callback = generateCallbackMethod(method.getDefinition(), method.getHolder());
+    method.getHolder().addVirtualMethod(callback.getDefinition());
+    return callback;
   }
 
   public boolean shouldRegisterCallback(ProgramMethod method) {
@@ -370,7 +198,6 @@
     DexEncodedMethod definition = method.getDefinition();
     if (definition.isPrivateMethod()
         || definition.isStatic()
-        || definition.isAbstract()
         || definition.isLibraryMethodOverride().isFalse()) {
       return false;
     }
@@ -495,9 +322,19 @@
     return appView.dexItemFactory().createMethod(holder, newProto, originalMethod.name);
   }
 
-  public void ensureWrappersForL8(CfInstructionDesugaringEventConsumer eventConsumer) {
-    assert appView.options().isDesugaredLibraryCompilation();
-    wrapperSynthesizor.ensureWrappersForL8(eventConsumer);
+  public void finalizeWrappers(
+      DexApplication.Builder<?> builder, IRConverter irConverter, ExecutorService executorService)
+      throws ExecutionException {
+    // In D8, we generate the wrappers here. In R8, wrappers have already been generated in the
+    // enqueuer, so nothing needs to be done.
+    if (appView.enableWholeProgramOptimizations()) {
+      return;
+    }
+    SortedProgramMethodSet callbacks = generateCallbackMethods();
+    irConverter.processMethodsConcurrently(callbacks, executorService);
+    if (appView.options().isDesugaredLibraryCompilation()) {
+      wrapperSynthesizor.finalizeWrappersForL8();
+    }
   }
 
   public SortedProgramMethodSet generateCallbackMethods() {
@@ -508,7 +345,7 @@
           List<DexEncodedMethod> newVirtualMethods = new ArrayList<>();
           callbacks.forEach(
               callback -> {
-                ProgramMethod callbackMethod = generateCallbackMethod(callback, clazz, null);
+                ProgramMethod callbackMethod = generateCallbackMethod(callback, clazz);
                 newVirtualMethods.add(callbackMethod.getDefinition());
                 allCallbackMethods.add(callbackMethod);
               });
@@ -532,14 +369,12 @@
   }
 
   private ProgramMethod generateCallbackMethod(
-      DexEncodedMethod originalMethod,
-      DexProgramClass clazz,
-      DesugaredLibraryAPIConverterPostProcessingEventConsumer eventConsumer) {
+      DexEncodedMethod originalMethod, DexProgramClass clazz) {
     DexMethod methodToInstall =
         methodWithVivifiedTypeInSignature(originalMethod.getReference(), clazz.type, appView);
     CfCode cfCode =
         new APIConverterWrapperCfCodeProvider(
-                appView, originalMethod.getReference(), null, this, clazz.isInterface(), null)
+                appView, originalMethod.getReference(), null, this, clazz.isInterface())
             .generateCfCode();
     DexEncodedMethod newMethod =
         wrapperSynthesizor.newSynthesizedMethod(methodToInstall, originalMethod, cfCode);
@@ -547,13 +382,7 @@
     if (originalMethod.isLibraryMethodOverride().isTrue()) {
       newMethod.setLibraryMethodOverride(OptionalBool.TRUE);
     }
-    ProgramMethod callback = new ProgramMethod(clazz, newMethod);
-    if (eventConsumer != null) {
-      eventConsumer.acceptAPIConversionCallback(callback);
-    } else {
-      assert appView.enableWholeProgramOptimizations();
-    }
-    return callback;
+    return new ProgramMethod(clazz, newMethod);
   }
 
   private void generateTrackDesugaredAPIWarnings(Set<DexMethod> tracked, String inner) {
@@ -596,10 +425,8 @@
     return vivifiedType;
   }
 
-  public void registerWrappersForLibraryInvokeIfRequired(
-      DexMethod invokedMethod, Type invokeType, ProgramMethod context) {
-    // TODO(b/191656218): Once R8 support is done, use an unboxed boolean here.
-    if (!shouldRewriteInvoke(invokedMethod, invokeType, null, context)) {
+  public void registerWrappersForLibraryInvokeIfRequired(DexMethod invokedMethod) {
+    if (!shouldRewriteInvoke(invokedMethod)) {
       return;
     }
     if (trackedAPIs != null) {
@@ -616,120 +443,6 @@
     }
   }
 
-  private DexMethod computeReturnConversion(
-      DexMethod invokedMethod, CfInstructionDesugaringEventConsumer eventConsumer) {
-    DexType returnType = invokedMethod.proto.returnType;
-    if (!appView.rewritePrefix.hasRewrittenType(returnType, appView)) {
-      return null;
-    }
-    if (canConvert(returnType)) {
-      DexType newReturnType = DesugaredLibraryAPIConverter.vivifiedTypeFor(returnType, appView);
-      return ensureConversionMethod(returnType, newReturnType, returnType, eventConsumer);
-    }
-    reportInvalidInvoke(returnType, invokedMethod, "return ");
-    return null;
-  }
-
-  private DexMethod[] computeParameterConversions(
-      DexMethod invokedMethod, CfInstructionDesugaringEventConsumer eventConsumer) {
-    DexMethod[] parameterConversions = new DexMethod[invokedMethod.getArity()];
-    DexType[] parameters = invokedMethod.proto.parameters.values;
-    for (int i = 0; i < parameters.length; i++) {
-      DexType argType = parameters[i];
-      if (appView.rewritePrefix.hasRewrittenType(argType, appView)) {
-        if (canConvert(argType)) {
-          DexType argVivifiedType = vivifiedTypeFor(argType, appView);
-          parameterConversions[i] =
-              ensureConversionMethod(argType, argType, argVivifiedType, eventConsumer);
-        } else {
-          reportInvalidInvoke(argType, invokedMethod, "parameter ");
-        }
-      }
-    }
-    return parameterConversions;
-  }
-
-  private CfInvoke rewriteLibraryInvoke(
-      CfInvoke invoke,
-      MethodProcessingContext methodProcessingContext,
-      CfInstructionDesugaringEventConsumer eventConsumer,
-      ProgramMethod context) {
-    DexMethod invokedMethod = invoke.getMethod();
-    if (trackedAPIs != null) {
-      trackedAPIs.add(invokedMethod);
-    }
-    DexProto newProto =
-        invoke.isInvokeStatic()
-            ? invokedMethod.proto
-            : factory.prependTypeToProto(invokedMethod.getHolderType(), invokedMethod.getProto());
-    DexMethod apiConversionMethod =
-        invoke.isInvokeSuper(context.getHolderType())
-            ? createSuperAPIConversion(
-                invoke, methodProcessingContext, eventConsumer, newProto, context)
-            : createOutlinedAPIConversion(invoke, methodProcessingContext, eventConsumer, newProto);
-    return new CfInvoke(Opcodes.INVOKESTATIC, apiConversionMethod, false);
-  }
-
-  private DexMethod createSuperAPIConversion(
-      CfInvoke invoke,
-      MethodProcessingContext methodProcessingContext,
-      CfInstructionDesugaringEventConsumer eventConsumer,
-      DexProto newProto,
-      ProgramMethod context) {
-    DexMethod invokedMethod = invoke.getMethod();
-    String uniqueSuffix = methodProcessingContext.createUniqueContext().getSyntheticSuffix();
-    DexMethod method =
-        factory.createMethod(
-            context.getHolderType(), newProto, SUPER_CONVERSION_METHOD_PREFIX + uniqueSuffix);
-    DexEncodedMethod apiConversion =
-        new DexEncodedMethod(
-            method,
-            superAPIConversionMethodAccessFlags,
-            MethodTypeSignature.noSignature(),
-            DexAnnotationSet.empty(),
-            ParameterAnnotationsList.empty(),
-            new APIConversionCfCodeProvider(
-                    appView,
-                    method.holder,
-                    invoke,
-                    computeReturnConversion(invokedMethod, eventConsumer),
-                    computeParameterConversions(invokedMethod, eventConsumer))
-                .generateCfCode(),
-            true);
-    eventConsumer.acceptSuperAPIConversion(new ProgramMethod(context.getHolder(), apiConversion));
-    return method;
-  }
-
-  private DexMethod createOutlinedAPIConversion(
-      CfInvoke invoke,
-      MethodProcessingContext methodProcessingContext,
-      CfInstructionDesugaringEventConsumer eventConsumer,
-      DexProto newProto) {
-    DexMethod invokedMethod = invoke.getMethod();
-    ProgramMethod outline =
-        appView
-            .getSyntheticItems()
-            .createMethod(
-                SyntheticKind.API_CONVERSION,
-                methodProcessingContext.createUniqueContext(),
-                appView,
-                builder ->
-                    builder
-                        .setProto(newProto)
-                        .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
-                        .setCode(
-                            methodSig ->
-                                new APIConversionCfCodeProvider(
-                                        appView,
-                                        methodSig.holder,
-                                        invoke,
-                                        computeReturnConversion(invokedMethod, eventConsumer),
-                                        computeParameterConversions(invokedMethod, eventConsumer))
-                                    .generateCfCode()));
-    eventConsumer.acceptAPIConversion(outline);
-    return outline.getReference();
-  }
-
   private void rewriteLibraryInvoke(
       IRCode code,
       InvokeMethod invokeMethod,
@@ -861,7 +574,7 @@
 
   private Instruction createParameterConversion(
       IRCode code, DexType argType, DexType argVivifiedType, Value inValue) {
-    DexMethod conversionMethod = ensureConversionMethod(argType, argType, argVivifiedType, null);
+    DexMethod conversionMethod = ensureConversionMethod(argType, argType, argVivifiedType);
     // The value is null only if the input is null.
     Value convertedValue =
         createConversionValue(code, inValue.getType().nullability(), argVivifiedType, null);
@@ -870,8 +583,7 @@
 
   private Instruction createReturnConversionAndReplaceUses(
       IRCode code, InvokeMethod invokeMethod, DexType returnType, DexType returnVivifiedType) {
-    DexMethod conversionMethod =
-        ensureConversionMethod(returnType, returnVivifiedType, returnType, null);
+    DexMethod conversionMethod = ensureConversionMethod(returnType, returnVivifiedType, returnType);
     Value outValue = invokeMethod.outValue();
     Value convertedValue =
         createConversionValue(code, Nullability.maybeNull(), returnType, outValue.getLocalInfo());
@@ -888,11 +600,7 @@
     }
   }
 
-  public DexMethod ensureConversionMethod(
-      DexType type,
-      DexType srcType,
-      DexType destType,
-      DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+  public DexMethod ensureConversionMethod(DexType type, DexType srcType, DexType destType) {
     // ConversionType holds the methods "rewrittenType convert(type)" and the other way around.
     // But everything is going to be rewritten, so we need to use vivifiedType and type".
     DexType conversionHolder =
@@ -900,8 +608,8 @@
     if (conversionHolder == null) {
       conversionHolder =
           type == srcType
-              ? wrapperSynthesizor.ensureTypeWrapper(type, eventConsumer)
-              : wrapperSynthesizor.ensureVivifiedTypeWrapper(type, eventConsumer);
+              ? wrapperSynthesizor.ensureTypeWrapper(type)
+              : wrapperSynthesizor.ensureVivifiedTypeWrapper(type);
     }
     assert conversionHolder != null;
     return factory.createMethod(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverterEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverterEventConsumer.java
deleted file mode 100644
index 65f5ece..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverterEventConsumer.java
+++ /dev/null
@@ -1,25 +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.desugaredlibrary;
-
-import com.android.tools.r8.graph.DexClasspathClass;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.ProgramMethod;
-
-public interface DesugaredLibraryAPIConverterEventConsumer {
-
-  void acceptWrapperProgramClass(DexProgramClass clazz);
-
-  void acceptWrapperClasspathClass(DexClasspathClass clazz);
-
-  void acceptAPIConversion(ProgramMethod method);
-
-  void acceptSuperAPIConversion(ProgramMethod method);
-
-  interface DesugaredLibraryAPIConverterPostProcessingEventConsumer {
-
-    void acceptAPIConversionCallback(ProgramMethod method);
-  }
-}
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 dac3079..0b0039e 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,8 +23,6 @@
 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
@@ -43,9 +41,7 @@
   }
 
   @Override
-  public void postProcessingDesugaring(
-      CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
-      throws ExecutionException {
+  public void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) {
     if (appView.options().isDesugaredLibraryCompilation()) {
       ensureEmulatedDispatchMethodsSynthesized(eventConsumer);
     } else {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java
index 02eb59b..1f8322f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java
@@ -150,7 +150,6 @@
               .setCode(
                   methodSig ->
                       new EmulateInterfaceSyntheticCfCodeProvider(
-                              methodSig.getHolderType(),
                               emulatedDispatchMethod.getHolderType(),
                               desugarMethod,
                               itfMethod,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java
index 7e2164f..6c1e889 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java
@@ -117,16 +117,14 @@
     return appView.options().desugaredLibraryConfiguration.getWrapperConversions().contains(type);
   }
 
-  DexType ensureTypeWrapper(DexType type, DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
-    return ensureWrappers(type, eventConsumer).getWrapper().type;
+  DexType ensureTypeWrapper(DexType type) {
+    return ensureWrappers(type).getWrapper().type;
   }
 
-  DexType ensureVivifiedTypeWrapper(
-      DexType type, DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
-    return ensureWrappers(type, eventConsumer).getVivifiedWrapper().type;
+  DexType ensureVivifiedTypeWrapper(DexType type) {
+    return ensureWrappers(type).getVivifiedWrapper().type;
   }
 
-
   public void registerWrapper(DexType type) {
     wrappersToGenerate.add(type);
     assert getValidClassToWrap(type) != null;
@@ -163,17 +161,13 @@
     }
   }
 
-  private Wrappers ensureWrappers(
-      DexType type, DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+  private Wrappers ensureWrappers(DexType type) {
     assert canGenerateWrapper(type) : type;
     DexClass dexClass = getValidClassToWrap(type);
-    return ensureWrappers(dexClass, ignored -> {}, eventConsumer);
+    return ensureWrappers(dexClass, ignored -> {});
   }
 
-  private Wrappers ensureWrappers(
-      DexClass context,
-      Consumer<DexClasspathClass> creationCallback,
-      DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+  private Wrappers ensureWrappers(DexClass context, Consumer<DexClasspathClass> creationCallback) {
     DexType type = context.type;
     DexClass wrapper;
     DexClass vivifiedWrapper;
@@ -186,20 +180,15 @@
               vivifiedTypeFor(type),
               type,
               programContext,
-              eventConsumer,
-              wrapperField ->
-                  synthesizeVirtualMethodsForTypeWrapper(
-                      programContext, wrapperField, eventConsumer));
+              wrapperField -> synthesizeVirtualMethodsForTypeWrapper(programContext, wrapperField));
       vivifiedWrapper =
           ensureProgramWrapper(
               SyntheticKind.VIVIFIED_WRAPPER,
               type,
               vivifiedTypeFor(type),
               programContext,
-              eventConsumer,
               wrapperField ->
-                  synthesizeVirtualMethodsForVivifiedTypeWrapper(
-                      programContext, wrapperField, eventConsumer));
+                  synthesizeVirtualMethodsForVivifiedTypeWrapper(programContext, wrapperField));
       DexField wrapperField = getWrapperUniqueField(wrapper);
       DexField vivifiedWrapperField = getWrapperUniqueField(vivifiedWrapper);
       ensureProgramConversionMethod(
@@ -216,9 +205,7 @@
               type,
               classpathOrLibraryContext,
               creationCallback,
-              eventConsumer,
-              wrapperField ->
-                  synthesizeVirtualMethodsForTypeWrapper(context, wrapperField, eventConsumer));
+              wrapperField -> synthesizeVirtualMethodsForTypeWrapper(context, wrapperField));
       vivifiedWrapper =
           ensureClasspathWrapper(
               SyntheticKind.VIVIFIED_WRAPPER,
@@ -226,10 +213,8 @@
               vivifiedTypeFor(type),
               classpathOrLibraryContext,
               creationCallback,
-              eventConsumer,
               wrapperField ->
-                  synthesizeVirtualMethodsForVivifiedTypeWrapper(
-                      context, wrapperField, eventConsumer));
+                  synthesizeVirtualMethodsForVivifiedTypeWrapper(context, wrapperField));
       DexField wrapperField = getWrapperUniqueField(wrapper);
       DexField vivifiedWrapperField = getWrapperUniqueField(vivifiedWrapper);
       ensureClasspathConversionMethod(
@@ -257,7 +242,6 @@
       DexType wrappingType,
       DexType wrappedType,
       DexProgramClass programContext,
-      DesugaredLibraryAPIConverterEventConsumer eventConsumer,
       Function<DexEncodedField, DexEncodedMethod[]> virtualMethodProvider) {
     return appView
         .getSyntheticItems()
@@ -268,13 +252,9 @@
             builder -> buildWrapper(wrappingType, wrappedType, programContext, builder),
             // The creation of virtual methods may require new wrappers, this needs to happen
             // once the wrapper is created to avoid infinite recursion.
-            wrapper -> {
-              if (eventConsumer != null) {
-                eventConsumer.acceptWrapperProgramClass(wrapper);
-              }
-              wrapper.setVirtualMethods(
-                  virtualMethodProvider.apply(getWrapperUniqueEncodedField(wrapper)));
-            });
+            wrapper ->
+                wrapper.setVirtualMethods(
+                    virtualMethodProvider.apply(getWrapperUniqueEncodedField(wrapper))));
   }
 
   private DexClasspathClass ensureClasspathWrapper(
@@ -283,7 +263,6 @@
       DexType wrappedType,
       ClasspathOrLibraryClass classpathOrLibraryContext,
       Consumer<DexClasspathClass> creationCallback,
-      DesugaredLibraryAPIConverterEventConsumer eventConsumer,
       Function<DexEncodedField, DexEncodedMethod[]> virtualMethodProvider) {
     return appView
         .getSyntheticItems()
@@ -297,9 +276,6 @@
             // The creation of virtual methods may require new wrappers, this needs to happen
             // once the wrapper is created to avoid infinite recursion.
             wrapper -> {
-              if (eventConsumer != null) {
-                eventConsumer.acceptWrapperClasspathClass(wrapper);
-              }
               wrapper.setVirtualMethods(
                   virtualMethodProvider.apply(getWrapperUniqueEncodedField(wrapper)));
               creationCallback.accept(wrapper);
@@ -406,9 +382,7 @@
   }
 
   private DexEncodedMethod[] synthesizeVirtualMethodsForVivifiedTypeWrapper(
-      DexClass dexClass,
-      DexEncodedField wrapperField,
-      DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+      DexClass dexClass, DexEncodedField wrapperField) {
     List<DexEncodedMethod> dexMethods = allImplementedMethods(dexClass);
     List<DexEncodedMethod> generatedMethods = new ArrayList<>();
     // Each method should use only types in their signature, but each method the wrapper forwards
@@ -447,12 +421,7 @@
       } else {
         cfCode =
             new APIConverterVivifiedWrapperCfCodeProvider(
-                    appView,
-                    methodToInstall,
-                    wrapperField.getReference(),
-                    converter,
-                    isInterface,
-                    eventConsumer)
+                    appView, methodToInstall, wrapperField.getReference(), converter, isInterface)
                 .generateCfCode();
       }
       DexEncodedMethod newDexEncodedMethod =
@@ -463,9 +432,7 @@
   }
 
   private DexEncodedMethod[] synthesizeVirtualMethodsForTypeWrapper(
-      DexClass dexClass,
-      DexEncodedField wrapperField,
-      DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+      DexClass dexClass, DexEncodedField wrapperField) {
     List<DexEncodedMethod> dexMethods = allImplementedMethods(dexClass);
     List<DexEncodedMethod> generatedMethods = new ArrayList<>();
     // Each method should use only vivified types in their signature, but each method the wrapper
@@ -498,8 +465,7 @@
                     dexEncodedMethod.getReference(),
                     wrapperField.getReference(),
                     converter,
-                    isInterface,
-                    eventConsumer)
+                    isInterface)
                 .generateCfCode();
       }
       DexEncodedMethod newDexEncodedMethod =
@@ -608,7 +574,7 @@
         field, fieldAccessFlags, FieldTypeSignature.noSignature(), DexAnnotationSet.empty(), null);
   }
 
-  void ensureWrappersForL8(DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+  void finalizeWrappersForL8() {
     DesugaredLibraryConfiguration conf = appView.options().desugaredLibraryConfiguration;
     for (DexType type : conf.getWrapperConversions()) {
       assert !conf.getCustomConversions().containsKey(type);
@@ -616,7 +582,7 @@
       // In broken set-ups we can end up having a json files containing wrappers of non desugared
       // classes. Such wrappers are not required since the class won't be rewritten.
       if (validClassToWrap.isProgramClass()) {
-        ensureWrappers(validClassToWrap, ignored -> {}, eventConsumer);
+        ensureWrappers(validClassToWrap, ignored -> {});
       }
     }
   }
@@ -633,8 +599,7 @@
             classpathWrapper -> {
               changed.set(true);
               synthesizedCallback.accept(classpathWrapper);
-            },
-            null);
+            });
       }
     }
   }
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 14e5fea..d86d22c 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,8 +380,7 @@
   }
 
   @Override
-  public void process(
-      DexProgramClass clazz, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
+  public void process(DexProgramClass clazz, ProgramMethodSet synthesizedMethods) {
     if (!clazz.isInterface()) {
       visitClassInfo(clazz, new ReportingContext(clazz, clazz));
     }
@@ -390,11 +389,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(InterfaceProcessingDesugaringEventConsumer eventConsumer) {
+  public final void finalizeProcessing(ProgramMethodSet synthesizedMethods) {
     newSyntheticMethods.forEach(
         (clazz, newForwardingMethods) -> {
           clazz.addVirtualMethods(newForwardingMethods.toDefinitionSet());
-          newForwardingMethods.forEach(eventConsumer::acceptForwardingMethod);
+          newForwardingMethods.forEach(synthesizedMethods::add);
         });
   }
 
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 f0d298f..46bd871 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,6 +19,7 @@
 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;
@@ -88,7 +89,7 @@
   }
 
   DexProgramClass ensureEmulateInterfaceLibrary(
-      DexProgramClass emulatedInterface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
+      DexProgramClass emulatedInterface, ProgramMethodSet synthesizedMethods) {
     assert rewriter.isEmulatedInterface(emulatedInterface.type);
     DexProgramClass emulateInterfaceClass =
         appView
@@ -106,7 +107,7 @@
                                     synthesizeEmulatedInterfaceMethod(
                                         method, emulatedInterface, methodBuilder))),
                 ignored -> {});
-    emulateInterfaceClass.forEachProgramMethod(eventConsumer::acceptEmulatedInterfaceMethod);
+    emulateInterfaceClass.forEachProgramMethod(synthesizedMethods::add);
     assert emulateInterfaceClass.getType()
         == InterfaceMethodRewriter.getEmulateLibraryInterfaceClassType(
             emulatedInterface.type, appView.dexItemFactory());
@@ -130,10 +131,9 @@
         .setProto(emulatedMethod.getProto())
         .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
         .setCode(
-            emulatedInterfaceMethod ->
+            theMethod ->
                 new EmulateInterfaceSyntheticCfCodeProvider(
-                        emulatedInterfaceMethod.getHolderType(),
-                        method.getHolderType(),
+                        theMethod.getHolderType(),
                         companionMethod,
                         libraryMethod,
                         extraDispatchCases,
@@ -177,22 +177,17 @@
       for (int i = subInterfaces.size() - 1; i >= 0; i--) {
         DexClass subInterfaceClass = appView.definitionFor(subInterfaces.get(i));
         assert subInterfaceClass != null;
+        assert subInterfaceClass.isProgramClass();
         // Else computation of subInterface would have failed.
         // if the method is implemented, extra dispatch is required.
         DexEncodedMethod result = subInterfaceClass.lookupVirtualMethod(method.getReference());
         if (result != null && !result.isAbstract()) {
+          assert result.isDefaultMethod();
           extraDispatchCases.add(
               new Pair<>(
                   subInterfaceClass.type,
-                  appView
-                      .dexItemFactory()
-                      .createMethod(
-                          rewriter.getCompanionClassType(subInterfaceClass.type),
-                          appView
-                              .dexItemFactory()
-                              .protoWithDifferentFirstParameter(
-                                  companionMethod.proto, subInterfaceClass.type),
-                          companionMethod.name)));
+                  InterfaceMethodRewriter.defaultAsMethodOfCompanionClass(
+                      result.getReference(), appView.dexItemFactory())));
         }
       }
     } else {
@@ -217,15 +212,14 @@
   }
 
   @Override
-  public void process(
-      DexProgramClass emulatedInterface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
+  public void process(DexProgramClass emulatedInterface, ProgramMethodSet synthesizedMethods) {
     if (!appView.options().isDesugaredLibraryCompilation()
         || !rewriter.isEmulatedInterface(emulatedInterface.type)
         || appView.isAlreadyLibraryDesugared(emulatedInterface)) {
       return;
     }
     if (needsEmulateInterfaceLibrary(emulatedInterface)) {
-      ensureEmulateInterfaceLibrary(emulatedInterface, eventConsumer);
+      ensureEmulateInterfaceLibrary(emulatedInterface, synthesizedMethods);
     }
   }
 
@@ -234,7 +228,7 @@
   }
 
   @Override
-  public void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer) {
+  public void finalizeProcessing(ProgramMethodSet synthesizedMethods) {
     warnMissingEmulatedInterfaces();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java
new file mode 100644
index 0000000..81ec904
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java
@@ -0,0 +1,28 @@
+// 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;
+
+public class InterfaceDesugaringForTesting {
+
+  public static String getEmulateLibraryClassNameSuffix() {
+    return InterfaceMethodRewriter.EMULATE_LIBRARY_CLASS_NAME_SUFFIX;
+  }
+
+  public static String getCompanionClassNameSuffix() {
+    return InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+  }
+
+  public static String getDefaultMethodPrefix() {
+    return InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX;
+  }
+
+  public static String getPrivateMethodPrefix() {
+    return InterfaceMethodRewriter.PRIVATE_METHOD_PREFIX;
+  }
+
+  public static String getCompanionClassDescriptor(String descriptor) {
+    return InterfaceMethodRewriter.getCompanionClassDescriptor(descriptor);
+  }
+}
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 4f4ba32..7f3d047 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,6 +5,7 @@
 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 {
 
@@ -13,11 +14,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, InterfaceProcessingDesugaringEventConsumer eventConsumer);
+  void process(DexProgramClass clazz, ProgramMethodSet synthesizedMethods);
 
   // 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(InterfaceProcessingDesugaringEventConsumer eventConsumer);
+  void finalizeProcessing(ProgramMethodSet synthesizedMethods);
 }
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 71844b0..731316f 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,10 +6,7 @@
 
 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;
@@ -19,22 +16,21 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 
-public class InterfaceMethodProcessorFacade implements CfPostProcessingDesugaring {
+class InterfaceMethodProcessorFacade {
 
   private final AppView<?> appView;
-  private final Flavor flavour;
-  private final List<InterfaceDesugaringProcessor> interfaceDesugaringProcessors;
 
-  InterfaceMethodProcessorFacade(
-      AppView<?> appView, Flavor flavour, InterfaceMethodRewriter rewriter) {
+  InterfaceMethodProcessorFacade(AppView<?> appView) {
     this.appView = appView;
-    this.flavour = flavour;
-    interfaceDesugaringProcessors = instantiateInterfaceDesugaringProcessors(appView, rewriter);
   }
 
-  private List<InterfaceDesugaringProcessor> instantiateInterfaceDesugaringProcessors(
-      AppView<?> appView, InterfaceMethodRewriter rewriter) {
-
+  /** Runs the interfaceProcessor, the class processor and the emulated interface processor. */
+  void runInterfaceDesugaringProcessors(
+      InterfaceMethodRewriter rewriter,
+      IRConverter converter,
+      Flavor flavour,
+      ExecutorService executorService)
+      throws ExecutionException {
     // 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 =
@@ -50,47 +46,17 @@
     // classes if needed.
     InterfaceProcessor interfaceProcessor = new InterfaceProcessor(appView, rewriter);
 
-    // 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 {
+    // 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);
 
     SortedProgramMethodSet sortedSynthesizedMethods = SortedProgramMethodSet.createConcurrent();
-
-    @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;
-    }
+    processClassesConcurrently(
+        orderedInterfaceDesugaringProcessors, sortedSynthesizedMethods, flavour, executorService);
+    assert converter != null;
+    converter.processMethodsConcurrently(sortedSynthesizedMethods, executorService);
   }
 
   private boolean shouldProcess(DexProgramClass clazz, Flavor flavour) {
@@ -101,28 +67,22 @@
   }
 
   private void processClassesConcurrently(
-      InterfaceProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
+      List<InterfaceDesugaringProcessor> processors,
+      SortedProgramMethodSet sortedSynthesizedMethods,
+      Flavor flavour,
+      ExecutorService executorService)
       throws ExecutionException {
     ThreadUtils.processItems(
         Iterables.filter(
             appView.appInfo().classes(), (DexProgramClass clazz) -> shouldProcess(clazz, flavour)),
         clazz -> {
-          for (InterfaceDesugaringProcessor processor : interfaceDesugaringProcessors) {
-            processor.process(clazz, eventConsumer);
+          for (InterfaceDesugaringProcessor processor : processors) {
+            processor.process(clazz, sortedSynthesizedMethods);
           }
         },
         executorService);
-    for (InterfaceDesugaringProcessor processor : interfaceDesugaringProcessors) {
-      processor.finalizeProcessing(eventConsumer);
+    for (InterfaceDesugaringProcessor processor : processors) {
+      processor.finalizeProcessing(sortedSynthesizedMethods);
     }
   }
-
-  @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 e6471fe..6ab6f1f 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
@@ -120,11 +120,11 @@
 //
 public final class InterfaceMethodRewriter implements CfInstructionDesugaring {
 
-  // Public for testing.
-  public static final String EMULATE_LIBRARY_CLASS_NAME_SUFFIX = "$-EL";
-  public static final String COMPANION_CLASS_NAME_SUFFIX = "$-CC";
-  public static final String DEFAULT_METHOD_PREFIX = "$default$";
-  public static final String PRIVATE_METHOD_PREFIX = "$private$";
+  // Use InterfaceDesugaringForTesting for public accesses in tests.
+  static final String EMULATE_LIBRARY_CLASS_NAME_SUFFIX = "$-EL";
+  static final String COMPANION_CLASS_NAME_SUFFIX = "$-CC";
+  static final String DEFAULT_METHOD_PREFIX = "$default$";
+  static final String PRIVATE_METHOD_PREFIX = "$private$";
 
   private final AppView<?> appView;
   private final InternalOptions options;
@@ -1155,7 +1155,8 @@
     }
   }
 
-  public static String getCompanionClassDescriptor(String descriptor) {
+  // Use InterfaceDesugaringForTesting for public accesses in tests.
+  static String getCompanionClassDescriptor(String descriptor) {
     return descriptor.substring(0, descriptor.length() - 1) + COMPANION_CLASS_NAME_SUFFIX + ";";
   }
 
@@ -1167,10 +1168,6 @@
     return factory.createSynthesizedType(ccTypeDescriptor);
   }
 
-  public DexType getCompanionClassType(DexType type) {
-    return getCompanionClassType(type, factory);
-  }
-
   // Checks if `type` is a companion class.
   public static boolean isCompanionClassType(DexType type) {
     return type.descriptor.toString().endsWith(COMPANION_CLASS_NAME_SUFFIX + ";");
@@ -1379,15 +1376,11 @@
     this.synthesizedMethods.clear();
   }
 
-  public void runInterfaceDesugaringProcessorsForR8(
+  public void runInterfaceDesugaringProcessors(
       IRConverter converter, Flavor flavour, ExecutorService executorService)
       throws ExecutionException {
-    getPostProcessingDesugaring(flavour)
-        .runInterfaceDesugaringProcessorsForR8(converter, executorService);
-  }
-
-  public InterfaceMethodProcessorFacade getPostProcessingDesugaring(Flavor flavour) {
-    return new InterfaceMethodProcessorFacade(appView, flavour, this);
+    new InterfaceMethodProcessorFacade(appView)
+        .runInterfaceDesugaringProcessors(this, converter, flavour, executorService);
   }
 
   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
deleted file mode 100644
index 2581364..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java
+++ /dev/null
@@ -1,16 +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.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 2dd65a9..cb752ad 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,6 +47,7 @@
 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;
@@ -79,13 +80,12 @@
   }
 
   @Override
-  public void process(
-      DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
+  public void process(DexProgramClass iface, ProgramMethodSet synthesizedMethods) {
     if (!iface.isInterface()) {
       return;
     }
     analyzeBridges(iface);
-    ensureCompanionClassMethods(iface, eventConsumer);
+    ensureCompanionClassMethods(iface, synthesizedMethods);
   }
 
   private void analyzeBridges(DexProgramClass iface) {
@@ -99,8 +99,8 @@
   }
 
   private void ensureCompanionClassMethods(
-      DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
-    ensureCompanionClassInitializesInterface(iface, eventConsumer);
+      DexProgramClass iface, ProgramMethodSet synthesizedMethods) {
+    ensureCompanionClassInitializesInterface(iface, synthesizedMethods);
     // 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, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
+      DexProgramClass iface, ProgramMethodSet synthesizedMethods) {
     if (!hasStaticMethodThatTriggersNonTrivialClassInitializer(iface)) {
       return;
     }
@@ -146,7 +146,7 @@
             appView.dexItemFactory().createProto(appView.dexItemFactory().voidType),
             appView,
             methodBuilder -> createCompanionClassInitializer(iface, clinitField, methodBuilder));
-    eventConsumer.acceptCompanionClassClinit(clinit);
+    synthesizedMethods.add(clinit);
   }
 
   private DexEncodedField ensureStaticClinitFieldToTriggerInterfaceInitialization(
@@ -441,7 +441,7 @@
   }
 
   @Override
-  public void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer) {
+  public void finalizeProcessing(ProgramMethodSet synthesizedMethods) {
     InterfaceProcessorNestedGraphLens graphLens = postProcessInterfaces();
     if (appView.enableWholeProgramOptimizations() && graphLens != null) {
       appView.setGraphLens(graphLens);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
index b052672..87adb53 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.graph.DexClassAndMember;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMember;
 import com.android.tools.r8.graph.DexMethod;
@@ -33,6 +34,7 @@
 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.ProgramAdditions;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.google.common.collect.ImmutableList;
@@ -98,6 +100,121 @@
     }
   }
 
+  private static class BridgeAndTarget<T extends DexClassAndMember<?, ?>> {
+    private final DexMethod bridge;
+    private final T target;
+
+    public BridgeAndTarget(DexMethod bridge, T target) {
+      this.bridge = bridge;
+      this.target = target;
+      assert bridge.holder == target.getHolderType();
+    }
+
+    public DexMethod getBridge() {
+      return bridge;
+    }
+
+    public T getTarget() {
+      return target;
+    }
+
+    public boolean shouldAddBridge() {
+      return target.isProgramMember() && target.getHolder().lookupDirectMethod(bridge) == null;
+    }
+  }
+
+  @Override
+  public void prepare(ProgramMethod method, ProgramAdditions programAdditions) {
+    method
+        .getDefinition()
+        .getCode()
+        .asCfCode()
+        .getInstructions()
+        .forEach(
+            instruction -> {
+              if (instruction.isFieldInstruction()) {
+                DexField field = instruction.asFieldInstruction().getField();
+                if (needsDesugaring(field, method)) {
+                  prepareDesugarFieldInstruction(
+                      field,
+                      instruction.asFieldInstruction().isFieldGet(),
+                      method,
+                      programAdditions);
+                }
+              } else if (instruction.isInvoke()) {
+                DexMethod invokedMethod = instruction.asInvoke().getMethod();
+                if (needsDesugaring(invokedMethod, method)) {
+                  prepareDesugarMethodInstruction(invokedMethod, method, programAdditions);
+                }
+              }
+            });
+  }
+
+  private void prepareDesugarFieldInstruction(
+      DexField field, boolean isGet, ProgramMethod context, ProgramAdditions programAdditions) {
+    BridgeAndTarget<DexClassAndField> bridgeAndTarget =
+        bridgeAndTargetForDesugaring(field, isGet, context);
+    if (bridgeAndTarget == null || !bridgeAndTarget.shouldAddBridge()) {
+      return;
+    }
+
+    programAdditions.accept(
+        bridgeAndTarget.getBridge(),
+        () ->
+            AccessBridgeFactory.createFieldAccessorBridge(
+                bridgeAndTarget.getBridge(), bridgeAndTarget.getTarget().asProgramField(), isGet));
+  }
+
+  private void prepareDesugarMethodInstruction(
+      DexMethod method, ProgramMethod context, ProgramAdditions programAdditions) {
+    BridgeAndTarget<DexClassAndMethod> bridgeAndTarget =
+        bridgeAndTargetForDesugaring(method, context);
+    if (bridgeAndTarget == null || !bridgeAndTarget.shouldAddBridge()) {
+      return;
+    }
+    programAdditions.accept(
+        bridgeAndTarget.getBridge(),
+        () ->
+            bridgeAndTarget.getTarget().getDefinition().isInstanceInitializer()
+                ? AccessBridgeFactory.createInitializerAccessorBridge(
+                    bridgeAndTarget.getBridge(),
+                    bridgeAndTarget.getTarget().asProgramMethod(),
+                    dexItemFactory)
+                : AccessBridgeFactory.createMethodAccessorBridge(
+                    bridgeAndTarget.getBridge(),
+                    bridgeAndTarget.getTarget().asProgramMethod(),
+                    dexItemFactory));
+  }
+
+  private BridgeAndTarget<DexClassAndMethod> bridgeAndTargetForDesugaring(
+      DexMethod method, ProgramMethod context) {
+    if (!method.getHolderType().isClassType()) {
+      return null;
+    }
+    // Since we only need to desugar accesses to private methods, and all accesses to private
+    // methods must be accessing the private method directly on its holder, we can lookup the
+    // method on the holder instead of resolving the method.
+    DexClass holder = appView.definitionForHolder(method, context);
+    DexClassAndMethod target = method.lookupMemberOnClass(holder);
+    if (target == null || !needsDesugaring(target, context)) {
+      return null;
+    }
+    return new BridgeAndTarget<>(getMethodBridgeReference(target), target);
+  }
+
+  private BridgeAndTarget<DexClassAndField> bridgeAndTargetForDesugaring(
+      DexField field, boolean isGet, ProgramMethod context) {
+    // Since we only need to desugar accesses to private fields, and all accesses to private
+    // fields must be accessing the private field directly on its holder, we can lookup the
+    // field on the holder instead of resolving the field.
+    DexClass holder = appView.definitionForHolder(field, context);
+    DexClassAndField target = field.lookupMemberOnClass(holder);
+    if (target == null || !needsDesugaring(target, context)) {
+      return null;
+    }
+    return new BridgeAndTarget<>(getFieldAccessBridgeReference(target, isGet), target);
+  }
+
   public boolean needsDesugaring(ProgramMethod method) {
     if (!method.getHolder().isInANest() || !method.getDefinition().hasCode()) {
       return false;
@@ -166,18 +283,21 @@
       CfFieldInstruction instruction,
       ProgramMethod context,
       NestBasedAccessDesugaringEventConsumer eventConsumer) {
-    // Since we only need to desugar accesses to private fields, and all accesses to private
-    // fields must be accessing the private field directly on its holder, we can lookup the
-    // field on the holder instead of resolving the field.
-    DexClass holder = appView.definitionForHolder(instruction.getField(), context);
-    DexClassAndField field = instruction.getField().lookupMemberOnClass(holder);
-    if (field == null || !needsDesugaring(field, context)) {
+
+    BridgeAndTarget<DexClassAndField> bridgeAndTarget =
+        bridgeAndTargetForDesugaring(instruction.getField(), instruction.isFieldGet(), context);
+    if (bridgeAndTarget == null) {
       return null;
     }
-
-    DexMethod bridge = ensureFieldAccessBridge(field, instruction.isFieldGet(), eventConsumer);
+    // All bridges for program fields must have been added through the prepare step.
+    assert !bridgeAndTarget.getTarget().isProgramField()
+        || bridgeAndTarget.getTarget().getHolder().lookupDirectMethod(bridgeAndTarget.getBridge())
+            != null;
     return ImmutableList.of(
-        new CfInvoke(Opcodes.INVOKESTATIC, bridge, field.getHolder().isInterface()));
+        new CfInvoke(
+            Opcodes.INVOKESTATIC,
+            bridgeAndTarget.getBridge(),
+            bridgeAndTarget.getTarget().getHolder().isInterface()));
   }
 
   private List<CfInstruction> desugarInvokeInstruction(
@@ -186,29 +306,27 @@
       ProgramMethod context,
       NestBasedAccessDesugaringEventConsumer eventConsumer) {
     DexMethod invokedMethod = invoke.getMethod();
-    if (!invokedMethod.getHolderType().isClassType()) {
+
+    BridgeAndTarget<DexClassAndMethod> bridgeAndTarget =
+        bridgeAndTargetForDesugaring(invokedMethod, context);
+    if (bridgeAndTarget == null) {
       return null;
     }
-
-    // Since we only need to desugar accesses to private methods, and all accesses to private
-    // methods must be accessing the private method directly on its holder, we can lookup the
-    // method on the holder instead of resolving the method.
-    DexClass holder = appView.definitionForHolder(invokedMethod, context);
-    DexClassAndMethod target = invokedMethod.lookupMemberOnClass(holder);
-    if (target == null || !needsDesugaring(target, context)) {
-      return null;
-    }
-
-    DexMethod bridge = ensureMethodBridge(target, eventConsumer);
-    if (target.getDefinition().isInstanceInitializer()) {
+    // All bridges for program methods must have been added through the prepare step.
+    assert !bridgeAndTarget.getTarget().isProgramMethod()
+        || bridgeAndTarget.getTarget().getHolder().lookupDirectMethod(bridgeAndTarget.getBridge())
+            != null;
+    if (bridgeAndTarget.getTarget().getDefinition().isInstanceInitializer()) {
       assert !invoke.isInterface();
       // Ensure room on the stack for the extra null argument.
       localStackAllocator.allocateLocalStack(1);
       return ImmutableList.of(
-          new CfConstNull(), new CfInvoke(Opcodes.INVOKESPECIAL, bridge, false));
+          new CfConstNull(),
+          new CfInvoke(Opcodes.INVOKESPECIAL, bridgeAndTarget.getBridge(), false));
     }
 
-    return ImmutableList.of(new CfInvoke(Opcodes.INVOKESTATIC, bridge, invoke.isInterface()));
+    return ImmutableList.of(
+        new CfInvoke(Opcodes.INVOKESTATIC, bridgeAndTarget.getBridge(), invoke.isInterface()));
   }
 
   private RuntimeException reportIncompleteNest(LibraryMember<?, ?> member) {
@@ -279,6 +397,7 @@
     return dexItemFactory.createString(prefix + field.getName().toString());
   }
 
+  // This is only used for generating bridge methods for class path references.
   DexMethod ensureMethodBridge(
       DexClassAndMethod method, NestBasedAccessDesugaringEventConsumer eventConsumer) {
     if (method.isProgramMethod()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java
index 533174b..4fd2fcd 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java
@@ -56,7 +56,7 @@
   }
 
   @Override
-  public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApi) {
+  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
     throw new RuntimeException("Should never be called");
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java
index 27c6f43..a9c7462 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java
@@ -16,12 +16,12 @@
   }
 
   @Override
-  public boolean hasApiReferenceLevel() {
+  public boolean hasApiReferenceLevelForDefinition() {
     return true;
   }
 
   @Override
-  public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApi) {
+  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
     return minApi;
   }
 
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 2d8ff77..aebd195 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
@@ -197,12 +197,22 @@
   }
 
   @Override
-  public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApi) {
+  public boolean hasApiReferenceLevelForCode() {
+    return false;
+  }
+
+  @Override
+  public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi) {
     throw new RuntimeException("Should never be called");
   }
 
   @Override
-  public boolean hasApiReferenceLevel() {
+  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
+    throw new RuntimeException("Should never be called");
+  }
+
+  @Override
+  public boolean hasApiReferenceLevelForDefinition() {
     return false;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java
index 0638369..cd06dee 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java
@@ -16,12 +16,22 @@
   }
 
   @Override
-  public boolean hasApiReferenceLevel() {
+  public boolean hasApiReferenceLevelForDefinition() {
     return true;
   }
 
   @Override
-  public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApi) {
+  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
+    return minApi;
+  }
+
+  @Override
+  public boolean hasApiReferenceLevelForCode() {
+    return true;
+  }
+
+  @Override
+  public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi) {
     return minApi;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/FieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/FieldOptimizationInfo.java
index 8a098ac..8f42838 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/FieldOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/FieldOptimizationInfo.java
@@ -55,4 +55,14 @@
   public abstract boolean isDead();
 
   public abstract boolean valueHasBeenPropagated();
+
+  @Override
+  public boolean isFieldOptimizationInfo() {
+    return true;
+  }
+
+  @Override
+  public FieldOptimizationInfo asFieldOptimizationInfo() {
+    return this;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java
index 910669d..9cb8a2a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java
@@ -21,11 +21,27 @@
     return null;
   }
 
-  default boolean hasApiReferenceLevel() {
+  default boolean hasApiReferenceLevelForDefinition() {
     return false;
   }
 
-  AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApi);
+  AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi);
 
   T toMutableOptimizationInfo();
+
+  default boolean isFieldOptimizationInfo() {
+    return false;
+  }
+
+  default boolean isMethodOptimizationInfo() {
+    return false;
+  }
+
+  default FieldOptimizationInfo asFieldOptimizationInfo() {
+    return null;
+  }
+
+  default MethodOptimizationInfo asMethodOptimizationInfo() {
+    return null;
+  }
 }
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 4de895c..30c8d7a 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
@@ -17,6 +17,7 @@
 import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
 import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
 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;
@@ -103,17 +104,31 @@
 
   public abstract boolean returnValueHasBeenPropagated();
 
+  public abstract boolean hasApiReferenceLevelForCode();
+
+  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.hasApiReferenceLevel() || !inlinee.hasApiReferenceLevel()) {
+    if (!caller.hasApiReferenceLevelForCode() || !inlinee.hasApiReferenceLevelForCode()) {
       return UNKNOWN;
     }
     return OptionalBool.of(
         caller
-            .getApiReferenceLevel(options.minApiLevel)
-            .isGreaterThanOrEqualTo(inlinee.getApiReferenceLevel(options.minApiLevel)));
+            .getApiReferenceLevelForCode(options.minApiLevel)
+            .isGreaterThanOrEqualTo(inlinee.getApiReferenceLevelForCode(options.minApiLevel)));
+  }
+
+  @Override
+  public boolean isMethodOptimizationInfo() {
+    return true;
+  }
+
+  @Override
+  public MethodOptimizationInfo asMethodOptimizationInfo() {
+    return this;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
index d00377e..bdab6e8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
@@ -69,6 +69,7 @@
   public MutableFieldOptimizationInfo mutableCopy() {
     MutableFieldOptimizationInfo copy = new MutableFieldOptimizationInfo();
     copy.flags = flags;
+    copy.apiReferenceLevel = apiReferenceLevel;
     return copy;
   }
 
@@ -156,13 +157,13 @@
 
   @SuppressWarnings("OptionalAssignedToNull")
   @Override
-  public boolean hasApiReferenceLevel() {
+  public boolean hasApiReferenceLevelForDefinition() {
     return apiReferenceLevel != null;
   }
 
   @Override
-  public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApi) {
-    assert hasApiReferenceLevel();
+  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
+    assert hasApiReferenceLevelForDefinition();
     return apiReferenceLevel.orElse(minApi);
   }
 
@@ -174,7 +175,7 @@
   }
 
   @Override
-  public void setApiReferenceLevel(AndroidApiLevel apiReferenceLevel) {
+  public void setApiReferenceLevelForDefinition(AndroidApiLevel apiReferenceLevel) {
     assert apiReferenceLevel != null;
     this.apiReferenceLevel = Optional.of(apiReferenceLevel);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
index 348312f..0f81ec0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -75,7 +75,8 @@
   private SimpleInliningConstraint simpleInliningConstraint =
       NeverSimpleInliningConstraint.getInstance();
 
-  private Optional<AndroidApiLevel> apiReferenceLevel = null;
+  private Optional<AndroidApiLevel> codeApiReferenceLevel = null;
+  private Optional<AndroidApiLevel> definitionApiReferenceLevel = null;
 
   // To reduce the memory footprint of UpdatableMethodOptimizationInfo, all the boolean fields are
   // merged into a flag int field. The various static final FLAG fields indicate which bit is
@@ -158,7 +159,8 @@
     nonNullParamOnNormalExits = template.nonNullParamOnNormalExits;
     classInlinerConstraint = template.classInlinerConstraint;
     enumUnboxerMethodClassification = template.enumUnboxerMethodClassification;
-    apiReferenceLevel = template.apiReferenceLevel;
+    definitionApiReferenceLevel = template.definitionApiReferenceLevel;
+    codeApiReferenceLevel = template.codeApiReferenceLevel;
   }
 
   public MutableMethodOptimizationInfo fixupClassTypeReferences(
@@ -526,28 +528,47 @@
   }
 
   @Override
-  public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApi) {
-    assert hasApiReferenceLevel();
-    return apiReferenceLevel.orElse(minApi);
+  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
+    assert hasApiReferenceLevelForDefinition();
+    return definitionApiReferenceLevel.orElse(minApi);
   }
 
   @SuppressWarnings("OptionalAssignedToNull")
   @Override
-  public boolean hasApiReferenceLevel() {
-    return apiReferenceLevel != null;
+  public boolean hasApiReferenceLevelForDefinition() {
+    return definitionApiReferenceLevel != null;
+  }
+
+  @Override
+  @SuppressWarnings("OptionalAssignedToNull")
+  public boolean hasApiReferenceLevelForCode() {
+    return codeApiReferenceLevel != null;
+  }
+
+  @Override
+  public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi) {
+    assert hasApiReferenceLevelForCode();
+    return codeApiReferenceLevel.orElse(minApi);
   }
 
   @Override
   @SuppressWarnings("OptionalAssignedToNull")
   public void setMinApiReferenceLevel() {
-    assert apiReferenceLevel == null;
-    this.apiReferenceLevel = Optional.empty();
+    assert codeApiReferenceLevel == null;
+    assert definitionApiReferenceLevel == null;
+    this.codeApiReferenceLevel = Optional.empty();
+    this.definitionApiReferenceLevel = Optional.empty();
+  }
+
+  public void setApiReferenceLevelForCode(AndroidApiLevel apiLevel) {
+    assert apiLevel != null;
+    this.codeApiReferenceLevel = Optional.of(apiLevel);
   }
 
   @Override
-  public void setApiReferenceLevel(AndroidApiLevel apiReferenceLevel) {
-    assert apiReferenceLevel != null;
-    this.apiReferenceLevel = Optional.of(apiReferenceLevel);
+  public void setApiReferenceLevelForDefinition(AndroidApiLevel apiLevel) {
+    assert apiLevel != null;
+    this.definitionApiReferenceLevel = Optional.of(apiLevel);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java
index db7bd1d..421f689 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java
@@ -10,5 +10,5 @@
 
   void setMinApiReferenceLevel();
 
-  void setApiReferenceLevel(AndroidApiLevel apiReferenceLevel);
+  void setApiReferenceLevelForDefinition(AndroidApiLevel apiLevel);
 }
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
index 5680337..db93ced 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
@@ -32,8 +32,6 @@
 import com.android.tools.r8.ir.code.If;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverterEventConsumer;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.collections.ImmutableDeque;
 import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap;
 import java.util.ArrayList;
@@ -64,25 +62,22 @@
   public static class APIConverterVivifiedWrapperCfCodeProvider
       extends DesugaredLibraryAPIConversionCfCodeProvider {
 
-    private final DexField wrapperField;
-    private final DexMethod forwardMethod;
-    private final DesugaredLibraryAPIConverter converter;
-    private final boolean itfCall;
-    private final DesugaredLibraryAPIConverterEventConsumer eventConsumer;
+    DexField wrapperField;
+    DexMethod forwardMethod;
+    DesugaredLibraryAPIConverter converter;
+    boolean itfCall;
 
     public APIConverterVivifiedWrapperCfCodeProvider(
         AppView<?> appView,
         DexMethod forwardMethod,
         DexField wrapperField,
         DesugaredLibraryAPIConverter converter,
-        boolean itfCall,
-        DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+        boolean itfCall) {
       super(appView, wrapperField.holder);
       this.forwardMethod = forwardMethod;
       this.wrapperField = wrapperField;
       this.converter = converter;
       this.itfCall = itfCall;
-      this.eventConsumer = eventConsumer;
     }
 
     @Override
@@ -103,8 +98,7 @@
           instructions.add(
               new CfInvoke(
                   Opcodes.INVOKESTATIC,
-                  converter.ensureConversionMethod(
-                      param, param, vivifiedTypeFor(param), eventConsumer),
+                  converter.ensureConversionMethod(param, param, vivifiedTypeFor(param)),
                   false));
           newParameters[index - 1] = vivifiedTypeFor(param);
         }
@@ -136,7 +130,7 @@
             new CfInvoke(
                 Opcodes.INVOKESTATIC,
                 converter.ensureConversionMethod(
-                    returnType, vivifiedTypeFor(returnType), returnType, eventConsumer),
+                    returnType, vivifiedTypeFor(returnType), returnType),
                 false));
       }
       if (returnType == factory.voidType) {
@@ -155,22 +149,19 @@
     DexMethod forwardMethod;
     DesugaredLibraryAPIConverter converter;
     boolean itfCall;
-    private final DesugaredLibraryAPIConverterEventConsumer eventConsumer;
 
     public APIConverterWrapperCfCodeProvider(
         AppView<?> appView,
         DexMethod forwardMethod,
         DexField wrapperField,
         DesugaredLibraryAPIConverter converter,
-        boolean itfCall,
-        DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+        boolean itfCall) {
       //  Var wrapperField is null if should forward to receiver.
       super(appView, wrapperField == null ? forwardMethod.holder : wrapperField.holder);
       this.forwardMethod = forwardMethod;
       this.wrapperField = wrapperField;
       this.converter = converter;
       this.itfCall = itfCall;
-      this.eventConsumer = eventConsumer;
     }
 
     @Override
@@ -194,8 +185,7 @@
           instructions.add(
               new CfInvoke(
                   Opcodes.INVOKESTATIC,
-                  converter.ensureConversionMethod(
-                      param, vivifiedTypeFor(param), param, eventConsumer),
+                  converter.ensureConversionMethod(param, vivifiedTypeFor(param), param),
                   false));
         }
         if (param == factory.longType || param == factory.doubleType) {
@@ -216,7 +206,7 @@
             new CfInvoke(
                 Opcodes.INVOKESTATIC,
                 converter.ensureConversionMethod(
-                    returnType, returnType, vivifiedTypeFor(returnType), eventConsumer),
+                    returnType, returnType, vivifiedTypeFor(returnType)),
                 false));
         returnType = vivifiedTypeFor(returnType);
       }
@@ -292,105 +282,6 @@
     }
   }
 
-  public static class APIConversionCfCodeProvider extends SyntheticCfCodeProvider {
-
-    private final CfInvoke initialInvoke;
-    private final DexMethod returnConversion;
-    private final DexMethod[] parameterConversions;
-
-    public APIConversionCfCodeProvider(
-        AppView<?> appView,
-        DexType holder,
-        CfInvoke initialInvoke,
-        DexMethod returnConversion,
-        DexMethod[] parameterConversions) {
-      super(appView, holder);
-      this.initialInvoke = initialInvoke;
-      this.returnConversion = returnConversion;
-      this.parameterConversions = parameterConversions;
-    }
-
-    private DexType invalidType(DexMethod invokedMethod, DexMethod convertedMethod) {
-      if (invokedMethod.getReturnType() != convertedMethod.getReturnType()
-          && returnConversion == null) {
-        return invokedMethod.getReturnType();
-      }
-      for (int i = 0; i < invokedMethod.getArity(); i++) {
-        if (invokedMethod.getParameter(i) != convertedMethod.getParameter(i)
-            && parameterConversions[i] == null) {
-          return invokedMethod.getParameter(i);
-        }
-      }
-      return null;
-    }
-
-    @Override
-    public CfCode generateCfCode() {
-      DexMethod invokedMethod = initialInvoke.getMethod();
-      DexMethod convertedMethod =
-          DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature(
-              invokedMethod, invokedMethod.holder, appView);
-
-      DexType invalidType = invalidType(invokedMethod, convertedMethod);
-      if (invalidType != null) {
-        // This is true if the API conversion requires to convert a type which is impossible to
-        // convert: no custom conversion and no wrapping possible. This is extremely rare and
-        // should happen only with broken desugared library set-ups. A warning has already been
-        // reported at this point.
-        DexString message =
-            appView
-                .dexItemFactory()
-                .createString(
-                    "The method "
-                        + invokedMethod
-                        + " requires API conversion, but conversion was impossible because of the"
-                        + " non convertible type "
-                        + invalidType
-                        + ".");
-        return new APIConverterThrowRuntimeExceptionCfCodeProvider(
-                appView, message, invokedMethod.getHolderType())
-            .generateCfCode();
-      }
-
-      List<CfInstruction> instructions = new ArrayList<>();
-
-      boolean isStatic = initialInvoke.getOpcode() == Opcodes.INVOKESTATIC;
-      if (!isStatic) {
-        instructions.add(new CfLoad(ValueType.fromDexType(invokedMethod.holder), 0));
-      }
-      int receiverShift = BooleanUtils.intValue(!isStatic);
-      int stackIndex = 0;
-      for (int i = 0; i < invokedMethod.getArity(); i++) {
-        DexType param = invokedMethod.getParameter(i);
-        instructions.add(new CfLoad(ValueType.fromDexType(param), stackIndex + receiverShift));
-        if (parameterConversions[i] != null) {
-          instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, parameterConversions[i], false));
-        }
-        if (param == appView.dexItemFactory().longType
-            || param == appView.dexItemFactory().doubleType) {
-          stackIndex++;
-        }
-        stackIndex++;
-      }
-
-      // Actual call to converted value.
-      instructions.add(
-          new CfInvoke(initialInvoke.getOpcode(), convertedMethod, initialInvoke.isInterface()));
-
-      // Return conversion.
-      if (returnConversion != null) {
-        instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, returnConversion, false));
-      }
-
-      if (invokedMethod.getReturnType().isVoidType()) {
-        instructions.add(new CfReturnVoid());
-      } else {
-        instructions.add(new CfReturn(ValueType.fromDexType(invokedMethod.getReturnType())));
-      }
-      return standardCfCodeFromInstructions(instructions);
-    }
-  }
-
   public static class APIConverterConstructorCfCodeProvider extends SyntheticCfCodeProvider {
 
     DexField wrapperField;
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EmulateInterfaceSyntheticCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EmulateInterfaceSyntheticCfCodeProvider.java
index e1ba3b2..7f26a19 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EmulateInterfaceSyntheticCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EmulateInterfaceSyntheticCfCodeProvider.java
@@ -36,13 +36,12 @@
   private final List<Pair<DexType, DexMethod>> extraDispatchCases;
 
   public EmulateInterfaceSyntheticCfCodeProvider(
-      DexType holder,
       DexType interfaceType,
       DexMethod companionMethod,
       DexMethod libraryMethod,
       List<Pair<DexType, DexMethod>> extraDispatchCases,
       AppView<?> appView) {
-    super(appView, holder);
+    super(appView, interfaceType);
     this.interfaceType = interfaceType;
     this.companionMethod = companionMethod;
     this.libraryMethod = libraryMethod;
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 02aea63..822a7dc 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -105,6 +105,7 @@
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer.R8PostProcessingDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.LambdaClass;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
+import com.android.tools.r8.ir.desugar.ProgramAdditions;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.kotlin.KotlinMetadataEnqueuerExtension;
 import com.android.tools.r8.logging.Log;
@@ -3466,6 +3467,13 @@
     if (pendingDesugaring.isEmpty()) {
       return;
     }
+
+    // Prepare desugaring by collecting all the synthetic methods required on program classes.
+    ProgramAdditions programAdditions = new ProgramAdditions();
+    ThreadUtils.processItems(
+        pendingDesugaring, method -> desugaring.prepare(method, programAdditions), executorService);
+    programAdditions.apply(executorService);
+
     R8CfInstructionDesugaringEventConsumer desugaringEventConsumer =
         CfInstructionDesugaringEventConsumer.createForR8(
             appView,
@@ -3878,14 +3886,14 @@
     }
   }
 
-  private void postProcessingDesugaring() throws ExecutionException {
+  private void postProcessingDesugaring() {
     SyntheticAdditions syntheticAdditions =
         new SyntheticAdditions(appView.createProcessorContext());
 
     R8PostProcessingDesugaringEventConsumer eventConsumer =
         CfPostProcessingDesugaringEventConsumer.createForR8(appView, syntheticAdditions);
-    CfPostProcessingDesugaringCollection.create(appView, null, desugaring.getRetargetingInfo())
-        .postProcessingDesugaring(eventConsumer, executorService);
+    CfPostProcessingDesugaringCollection.create(appView, desugaring.getRetargetingInfo())
+        .postProcessingDesugaring(eventConsumer);
 
     if (syntheticAdditions.isEmpty()) {
       return;
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
index 4768437..2fcac55 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
@@ -18,8 +18,8 @@
 import com.android.tools.r8.utils.Action;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
-import java.util.ArrayDeque;
 import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
 
 public abstract class EnqueuerWorklist {
 
@@ -369,7 +369,7 @@
   static class PushableEnqueuerWorkList extends EnqueuerWorklist {
 
     PushableEnqueuerWorkList(Enqueuer enqueuer) {
-      super(enqueuer, new ArrayDeque<>());
+      super(enqueuer, new ConcurrentLinkedQueue<>());
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index 9f87beb..4c1ac7c 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -51,8 +51,7 @@
     THROW_NSME("ThrowNSME", 16, true),
     TWR_CLOSE_RESOURCE("TwrCloseResource", 17, true),
     SERVICE_LOADER("ServiceLoad", 18, true),
-    OUTLINE("Outline", 19, true),
-    API_CONVERSION("APIConversion", 26, true);
+    OUTLINE("Outline", 19, true);
 
     static {
       assert verifyNoOverlappingIds();
diff --git a/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java b/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java
index 4838419..5fe5cf1 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java
@@ -44,6 +44,10 @@
     return backing.get(method);
   }
 
+  public boolean contains(DexMethod method) {
+    return backing.containsKey(method);
+  }
+
   public boolean contains(DexEncodedMethod method) {
     return backing.containsKey(method.getReference());
   }
diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
index f13a704..dfebfd7 100644
--- a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8;
 
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
 import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
 import static org.junit.Assert.assertEquals;
 
@@ -13,7 +14,6 @@
 import com.android.tools.r8.errors.InternalCompilerError;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
@@ -97,7 +97,7 @@
           // interface, the main class/interface, or for JDK9, desugaring of try-with-resources.
           ClassReference reference = Reference.classFromDescriptor(descriptor);
           Assert.assertTrue(
-              descriptor.endsWith(InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX + ";")
+              descriptor.endsWith(getCompanionClassNameSuffix() + ";")
                   || SyntheticItemsTestUtils.isExternalTwrCloseMethod(reference)
                   || SyntheticItemsTestUtils.isExternalLambda(reference)
                   || SyntheticItemsTestUtils.isExternalStaticInterfaceCall(reference)
diff --git a/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java b/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
index fd7a3bd..a20964a 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8;
 
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getPrivateMethodPrefix;
 import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
 import static com.android.tools.r8.utils.FileUtils.ZIP_EXTENSION;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -13,7 +15,6 @@
 import static org.junit.Assume.assumeFalse;
 
 import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.TestDescriptionWatcher;
@@ -218,21 +219,24 @@
   public void desugaredPrivateInterfaceMethods() throws Throwable {
     assumeFalse("CF backend does not desugar", this instanceof R8CFRunExamplesJava9Test);
     final String iName = "privateinterfacemethods.I";
-    test("desugared-private-interface-methods",
-        "privateinterfacemethods", "PrivateInterfaceMethods")
+    test(
+            "desugared-private-interface-methods",
+            "privateinterfacemethods",
+            "PrivateInterfaceMethods")
         .withMinApiLevel(AndroidApiLevel.M.getLevel())
         .withKeepAll()
-        .withDexCheck(dexInspector -> {
-          ClassSubject companion = dexInspector.clazz(
-              iName + InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX);
-          assertThat(companion, isPresent());
-          MethodSubject iFoo = companion.method(
-              "java.lang.String",
-              InterfaceMethodRewriter.PRIVATE_METHOD_PREFIX + "iFoo",
-              ImmutableList.of(iName, "boolean"));
-          assertThat(iFoo, isPresent());
-          assertTrue(iFoo.getMethod().isPublicMethod());
-        })
+        .withDexCheck(
+            dexInspector -> {
+              ClassSubject companion = dexInspector.clazz(iName + getCompanionClassNameSuffix());
+              assertThat(companion, isPresent());
+              MethodSubject iFoo =
+                  companion.method(
+                      "java.lang.String",
+                      getPrivateMethodPrefix() + "iFoo",
+                      ImmutableList.of(iName, "boolean"));
+              assertThat(iFoo, isPresent());
+              assertTrue(iFoo.getMethod().isPublicMethod());
+            })
         .run();
   }
 
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 0a7edb3..f0d2830 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -197,6 +197,10 @@
     return Paths.get(getDesugarLibraryJsonDir(), "desugar_jdk_libs.json");
   }
 
+  public static Path getCHMOnlyDesugarLibJsonForTesting() {
+    return Paths.get(getDesugarLibraryJsonDir(), "chm_only_desugar_jdk_libs.json");
+  }
+
   public static Path getDesugarLibJsonForTestingAlternative3() {
     return Paths.get(getDesugarLibraryJsonDir(), "desugar_jdk_libs_alternative_3.json");
   }
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerDebugTestRunner.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerDebugTestRunner.java
index 210967c..8709781 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerDebugTestRunner.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerDebugTestRunner.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.classmerging.vertical;
 
-import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -52,7 +52,7 @@
     // applied) contain "$classmerging$.
     String qualifiedMethodSignature =
         state.getClassSignature() + "->" + state.getMethodName() + state.getMethodSignature();
-    boolean holderIsCompanionClass = state.getClassName().endsWith(COMPANION_CLASS_NAME_SUFFIX);
+    boolean holderIsCompanionClass = state.getClassName().endsWith(getCompanionClassNameSuffix());
     if (!holderIsCompanionClass) {
       assertThat(qualifiedMethodSignature, not(containsString("$classmerging$")));
     }
diff --git a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
index 5f4be39..927b5ba 100644
--- a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
@@ -4,10 +4,12 @@
 
 package com.android.tools.r8.debug;
 
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getDefaultMethodPrefix;
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.Command;
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -52,12 +54,12 @@
       defaultMethodName = "doSomething";
       defaultMethodThisName = "this";
     } else {
-      defaultMethodContainerClass = "InterfaceWithDefaultAndStaticMethods"
-          + InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+      defaultMethodContainerClass =
+          "InterfaceWithDefaultAndStaticMethods" + getCompanionClassNameSuffix();
       // IntelliJ's debugger does not know about the companion class. The only way to match it with
       // the source file or the desguared interface is to make it an inner class.
-      assertEquals('$', InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX.charAt(0));
-      defaultMethodName = InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX + "doSomething";
+      assertEquals('$', getCompanionClassNameSuffix().charAt(0));
+      defaultMethodName = getDefaultMethodPrefix() + "doSomething";
       defaultMethodThisName = "_this";
     }
 
@@ -121,8 +123,9 @@
     if (supportsDefaultMethod(config)) {
       staticMethodContainerClass = "InterfaceWithDefaultAndStaticMethods";
     } else {
-      staticMethodContainerClass = "InterfaceWithDefaultAndStaticMethods"
-          + InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+      staticMethodContainerClass =
+          "InterfaceWithDefaultAndStaticMethods"
+              + InterfaceDesugaringForTesting.getCompanionClassNameSuffix();
     }
 
     List<Command> commands = new ArrayList<>();
diff --git a/src/test/java/com/android/tools/r8/desugar/ConcurrencyTest.java b/src/test/java/com/android/tools/r8/desugar/ConcurrencyTest.java
index 380127b..848fc6d 100644
--- a/src/test/java/com/android/tools/r8/desugar/ConcurrencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/ConcurrencyTest.java
@@ -6,7 +6,6 @@
 import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
 import static org.junit.Assume.assumeTrue;
 
-import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.cf.CfVersion;
@@ -57,7 +56,8 @@
                 }));
     for (String s : new String[] {"a", "b", "c", "d", "e"}) {
       for (int i = 0; i < 10; i++) {
-        transformer.setPrivate(Host.class.getDeclaredMethod(s + "0" + i));
+        transformer.setPrivate(Host.class.getDeclaredMethod(s + "0" + i, int.class));
+        transformer.setPrivate(Host.class.getDeclaredField("f" + s + "0" + i));
       }
     }
 
@@ -76,100 +76,234 @@
 
   @Test
   public void testD8() throws Exception {
-    try {
-      testForD8(parameters.getBackend())
-          .addProgramClasses(getClasses())
-          .addProgramClassFileData(getTransformedClasses())
-          .compile();
-    } catch (CompilationFailedException e) {
-      if (e.getCause() instanceof ArrayIndexOutOfBoundsException) {
-        // TODO(b/192310793): This should not happen.
-        return;
-      }
-      throw e;
-    }
+    testForD8(parameters.getBackend())
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .compile();
   }
 
   @Test
   public void testR8() throws Exception {
     assumeTrue(parameters.getBackend().isDex());
 
-    try {
-      testForR8(parameters.getBackend())
-          .addProgramClasses(getClasses())
-          .addProgramClassFileData(getTransformedClasses())
-          .setMinApi(parameters.getApiLevel())
-          .addKeepAllClassesRule()
-          .compile();
-    } catch (CompilationFailedException e) {
-      if (e.getCause() instanceof AssertionError
-          && e.getCause()
-              .getStackTrace()[0]
-              .getClassName()
-              .equals(
-                  "com.android.tools.r8.ir.desugar.NonEmptyCfInstructionDesugaringCollection")) {
-        // TODO(b/192446461): This should not happen.
-        return;
-      }
-      throw e;
-    }
+    testForR8(parameters.getBackend())
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepAllClassesRule()
+        .compile();
   }
 
   static class Host {
-    /* will be private */ void a00() {}
-    /* will be private */ void a01() {}
-    /* will be private */ void a02() {}
-    /* will be private */ void a03() {}
-    /* will be private */ void a04() {}
-    /* will be private */ void a05() {}
-    /* will be private */ void a06() {}
-    /* will be private */ void a07() {}
-    /* will be private */ void a08() {}
-    /* will be private */ void a09() {}
+    /* will be private */ int fa00;
+    /* will be private */ int fa01;
+    /* will be private */ int fa02;
+    /* will be private */ int fa03;
+    /* will be private */ int fa04;
+    /* will be private */ int fa05;
+    /* will be private */ int fa06;
+    /* will be private */ int fa07;
+    /* will be private */ int fa08;
+    /* will be private */ int fa09;
 
-    /* will be private */ void b00() {}
-    /* will be private */ void b01() {}
-    /* will be private */ void b02() {}
-    /* will be private */ void b03() {}
-    /* will be private */ void b04() {}
-    /* will be private */ void b05() {}
-    /* will be private */ void b06() {}
-    /* will be private */ void b07() {}
-    /* will be private */ void b08() {}
-    /* will be private */ void b09() {}
+    /* will be private */ int fb00;
+    /* will be private */ int fb01;
+    /* will be private */ int fb02;
+    /* will be private */ int fb03;
+    /* will be private */ int fb04;
+    /* will be private */ int fb05;
+    /* will be private */ int fb06;
+    /* will be private */ int fb07;
+    /* will be private */ int fb08;
+    /* will be private */ int fb09;
 
-    /* will be private */ void c00() {}
-    /* will be private */ void c01() {}
-    /* will be private */ void c02() {}
-    /* will be private */ void c03() {}
-    /* will be private */ void c04() {}
-    /* will be private */ void c05() {}
-    /* will be private */ void c06() {}
-    /* will be private */ void c07() {}
-    /* will be private */ void c08() {}
-    /* will be private */ void c09() {}
+    /* will be private */ int fc00;
+    /* will be private */ int fc01;
+    /* will be private */ int fc02;
+    /* will be private */ int fc03;
+    /* will be private */ int fc04;
+    /* will be private */ int fc05;
+    /* will be private */ int fc06;
+    /* will be private */ int fc07;
+    /* will be private */ int fc08;
+    /* will be private */ int fc09;
 
-    /* will be private */ void d00() {}
-    /* will be private */ void d01() {}
-    /* will be private */ void d02() {}
-    /* will be private */ void d03() {}
-    /* will be private */ void d04() {}
-    /* will be private */ void d05() {}
-    /* will be private */ void d06() {}
-    /* will be private */ void d07() {}
-    /* will be private */ void d08() {}
-    /* will be private */ void d09() {}
+    /* will be private */ int fd00;
+    /* will be private */ int fd01;
+    /* will be private */ int fd02;
+    /* will be private */ int fd03;
+    /* will be private */ int fd04;
+    /* will be private */ int fd05;
+    /* will be private */ int fd06;
+    /* will be private */ int fd07;
+    /* will be private */ int fd08;
+    /* will be private */ int fd09;
 
-    /* will be private */ void e00() {}
-    /* will be private */ void e01() {}
-    /* will be private */ void e02() {}
-    /* will be private */ void e03() {}
-    /* will be private */ void e04() {}
-    /* will be private */ void e05() {}
-    /* will be private */ void e06() {}
-    /* will be private */ void e07() {}
-    /* will be private */ void e08() {}
-    /* will be private */ void e09() {}
+    /* will be private */ int fe00;
+    /* will be private */ int fe01;
+    /* will be private */ int fe02;
+    /* will be private */ int fe03;
+    /* will be private */ int fe04;
+    /* will be private */ int fe05;
+    /* will be private */ int fe06;
+    /* will be private */ int fe07;
+    /* will be private */ int fe08;
+    /* will be private */ int fe09;
+
+    /* will be private */ int a00(int x) {
+      return x;
+    }
+    /* will be private */ int a01(int x) {
+      return x;
+    }
+    /* will be private */ int a02(int x) {
+      return x;
+    }
+    /* will be private */ int a03(int x) {
+      return x;
+    }
+    /* will be private */ int a04(int x) {
+      return x;
+    }
+    /* will be private */ int a05(int x) {
+      return x;
+    }
+    /* will be private */ int a06(int x) {
+      return x;
+    }
+    /* will be private */ int a07(int x) {
+      return x;
+    }
+    /* will be private */ int a08(int x) {
+      return x;
+    }
+    /* will be private */ int a09(int x) {
+      return x;
+    }
+
+    /* will be private */ int b00(int x) {
+      return x;
+    }
+    /* will be private */ int b01(int x) {
+      return x;
+    }
+    /* will be private */ int b02(int x) {
+      return x;
+    }
+    /* will be private */ int b03(int x) {
+      return x;
+    }
+    /* will be private */ int b04(int x) {
+      return x;
+    }
+    /* will be private */ int b05(int x) {
+      return x;
+    }
+    /* will be private */ int b06(int x) {
+      return x;
+    }
+    /* will be private */ int b07(int x) {
+      return x;
+    }
+    /* will be private */ int b08(int x) {
+      return x;
+    }
+    /* will be private */ int b09(int x) {
+      return x;
+    }
+
+    /* will be private */ int c00(int x) {
+      return x;
+    }
+    /* will be private */ int c01(int x) {
+      return x;
+    }
+    /* will be private */ int c02(int x) {
+      return x;
+    }
+    /* will be private */ int c03(int x) {
+      return x;
+    }
+    /* will be private */ int c04(int x) {
+      return x;
+    }
+    /* will be private */ int c05(int x) {
+      return x;
+    }
+    /* will be private */ int c06(int x) {
+      return x;
+    }
+    /* will be private */ int c07(int x) {
+      return x;
+    }
+    /* will be private */ int c08(int x) {
+      return x;
+    }
+    /* will be private */ int c09(int x) {
+      return x;
+    }
+
+    /* will be private */ int d00(int x) {
+      return x;
+    }
+    /* will be private */ int d01(int x) {
+      return x;
+    }
+    /* will be private */ int d02(int x) {
+      return x;
+    }
+    /* will be private */ int d03(int x) {
+      return x;
+    }
+    /* will be private */ int d04(int x) {
+      return x;
+    }
+    /* will be private */ int d05(int x) {
+      return x;
+    }
+    /* will be private */ int d06(int x) {
+      return x;
+    }
+    /* will be private */ int d07(int x) {
+      return x;
+    }
+    /* will be private */ int d08(int x) {
+      return x;
+    }
+    /* will be private */ int d09(int x) {
+      return x;
+    }
+
+    /* will be private */ int e00(int x) {
+      return x;
+    }
+    /* will be private */ int e01(int x) {
+      return x;
+    }
+    /* will be private */ int e02(int x) {
+      return x;
+    }
+    /* will be private */ int e03(int x) {
+      return x;
+    }
+    /* will be private */ int e04(int x) {
+      return x;
+    }
+    /* will be private */ int e05(int x) {
+      return x;
+    }
+    /* will be private */ int e06(int x) {
+      return x;
+    }
+    /* will be private */ int e07(int x) {
+      return x;
+    }
+    /* will be private */ int e08(int x) {
+      return x;
+    }
+    /* will be private */ int e09(int x) {
+      return x;
+    }
 
     private void hello() {}
 
@@ -275,86 +409,191 @@
       new Host().hello();
       new Host().hello();
       new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
+      new Host().hello();
     }
   }
 
   static class A {
     public void foo() {
       // Will be virtual invoke to private methods.
-      new Host().a00();
-      new Host().a01();
-      new Host().a02();
-      new Host().a03();
-      new Host().a04();
-      new Host().a05();
-      new Host().a06();
-      new Host().a07();
-      new Host().a08();
-      new Host().a09();
+      Host host = new Host();
+      host.fa00 = host.a00(host.fa00);
+      host.fa01 = host.a01(host.fa01);
+      host.fa02 = host.a02(host.fa02);
+      host.fa03 = host.a03(host.fa03);
+      host.fa04 = host.a04(host.fa04);
+      host.fa05 = host.a05(host.fa05);
+      host.fa06 = host.a06(host.fa06);
+      host.fa07 = host.a07(host.fa07);
+      host.fa08 = host.a08(host.fa08);
+      host.fa09 = host.a09(host.fa09);
     }
   }
 
   static class B {
     public void foo() {
       // Will be virtual invoke to private methods.
-      new Host().b00();
-      new Host().b01();
-      new Host().b02();
-      new Host().b03();
-      new Host().b04();
-      new Host().b05();
-      new Host().b06();
-      new Host().b07();
-      new Host().b08();
-      new Host().b09();
+      Host host = new Host();
+      host.fb00 = host.b00(host.fb00);
+      host.fb01 = host.b01(host.fb01);
+      host.fb02 = host.b02(host.fb02);
+      host.fb03 = host.b03(host.fb03);
+      host.fb04 = host.b04(host.fb04);
+      host.fb05 = host.b05(host.fb05);
+      host.fb06 = host.b06(host.fb06);
+      host.fb07 = host.b07(host.fb07);
+      host.fb08 = host.b08(host.fb08);
+      host.fb09 = host.b09(host.fb09);
     }
   }
 
   static class C {
     public void foo() {
       // Will be virtual invoke to private methods.
-      new Host().c00();
-      new Host().c01();
-      new Host().c02();
-      new Host().c03();
-      new Host().c04();
-      new Host().c05();
-      new Host().c06();
-      new Host().c07();
-      new Host().c08();
-      new Host().c09();
+      Host host = new Host();
+      host.fc00 = host.c00(host.fc00);
+      host.fc01 = host.c01(host.fc01);
+      host.fc02 = host.c02(host.fc02);
+      host.fc03 = host.c03(host.fc03);
+      host.fc04 = host.c04(host.fc04);
+      host.fc05 = host.c05(host.fc05);
+      host.fc06 = host.c06(host.fc06);
+      host.fc07 = host.c07(host.fc07);
+      host.fc08 = host.c08(host.fc08);
+      host.fc09 = host.c09(host.fc09);
     }
   }
 
   static class D {
     public void foo() {
       // Will be virtual invoke to private methods.
-      new Host().d00();
-      new Host().d01();
-      new Host().d02();
-      new Host().d03();
-      new Host().d04();
-      new Host().d05();
-      new Host().d06();
-      new Host().d07();
-      new Host().d08();
-      new Host().d09();
+      Host host = new Host();
+      host.fd00 = host.d00(host.fd00);
+      host.fd01 = host.d01(host.fd01);
+      host.fd02 = host.d02(host.fd02);
+      host.fd03 = host.d03(host.fd03);
+      host.fd04 = host.d04(host.fd04);
+      host.fd05 = host.d05(host.fd05);
+      host.fd06 = host.d06(host.fd06);
+      host.fd07 = host.d07(host.fd07);
+      host.fd08 = host.d08(host.fd08);
+      host.fd09 = host.d09(host.fd09);
     }
   }
 
   static class E {
     public void foo() {
       // Will be virtual invoke to private methods.
-      new Host().e00();
-      new Host().e01();
-      new Host().e02();
-      new Host().e03();
-      new Host().e04();
-      new Host().e05();
-      new Host().e06();
-      new Host().e07();
-      new Host().e08();
-      new Host().e09();
+      Host host = new Host();
+      host.fe00 = host.e00(host.fe00);
+      host.fe01 = host.e01(host.fe01);
+      host.fe02 = host.e02(host.fe02);
+      host.fe03 = host.e03(host.fe03);
+      host.fe04 = host.e04(host.fe04);
+      host.fe05 = host.e05(host.fe05);
+      host.fe06 = host.e06(host.fe06);
+      host.fe07 = host.e07(host.fe07);
+      host.fe08 = host.e08(host.fe08);
+      host.fe09 = host.e09(host.fe09);
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java b/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java
index 2d396f7d..1c8d5b9 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java
@@ -3,11 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar;
 
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
+
 import com.android.tools.r8.DesugarTestConfiguration;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import java.util.concurrent.Callable;
@@ -24,16 +25,16 @@
 
   private final List<String> EXPECTED_RESULT_WITH_DESUGARING =
       ImmutableList.of(
-          WithAnonymousInner.class.getName() + InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX,
+          WithAnonymousInner.class.getName() + getCompanionClassNameSuffix(),
           "true",
-          WithLocalInner.class.getName() + InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX,
+          WithLocalInner.class.getName() + getCompanionClassNameSuffix(),
           "true");
 
   private final List<String> EXPECTED_RESULT_WITH_DESUGARING_B168697955 =
       ImmutableList.of(
-          WithAnonymousInner.class.getName() + InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX,
+          WithAnonymousInner.class.getName() + getCompanionClassNameSuffix(),
           "false",
-          WithLocalInner.class.getName() + InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX,
+          WithLocalInner.class.getName() + getCompanionClassNameSuffix(),
           "false");
 
   @Parameterized.Parameters(name = "{0}")
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
index fdca331..ddebca5 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
@@ -126,7 +126,7 @@
       Path desugaredLib =
           getDesugaredLibraryInCF(parameters, this::configurationForLibraryCompilation);
 
-      // Run on the JVM with desugared library on classpath.
+      // Run on the JVM with desuagred library on classpath.
       testForJvm()
           .addProgramFiles(jar)
           .addRunClasspathFiles(desugaredLib)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
new file mode 100644
index 0000000..dc995e3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.desugaredlibrary;
+
+import com.android.tools.r8.StringResource;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfigurationParser;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import java.util.Collections;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DesugaredLibraryCHMOnlyContentTest extends DesugaredLibraryTestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  }
+
+  public DesugaredLibraryCHMOnlyContentTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testDesugaredLibraryContentCHMOnlyD8() throws Exception {
+    Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
+    Assume.assumeTrue(isJDK11DesugaredLibrary());
+    Path desugaredLib =
+        buildDesugaredLibrary(
+            parameters.getApiLevel(),
+            "",
+            false,
+            Collections.emptyList(),
+            options -> {
+              options.desugaredLibraryConfiguration =
+                  chmOnlyConfiguration(options, true, parameters);
+            });
+    CodeInspector inspector = new CodeInspector(desugaredLib);
+    assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
+  }
+
+  @Test
+  public void testDesugaredLibraryContentCHMOnlyR8() throws Exception {
+    Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
+    Assume.assumeTrue(isJDK11DesugaredLibrary());
+    Path desugaredLib =
+        buildDesugaredLibrary(
+            parameters.getApiLevel(),
+            "-keep class * { *; }",
+            true,
+            Collections.emptyList(),
+            options -> {
+              options.desugaredLibraryConfiguration =
+                  chmOnlyConfiguration(options, true, parameters);
+            });
+    CodeInspector inspector = new CodeInspector(desugaredLib);
+    assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
+  }
+
+  DesugaredLibraryConfiguration chmOnlyConfiguration(
+      InternalOptions options, boolean libraryCompilation, TestParameters parameters) {
+    return new DesugaredLibraryConfigurationParser(
+            options.dexItemFactory(),
+            options.reporter,
+            libraryCompilation,
+            parameters.getApiLevel().getLevel())
+        .parse(StringResource.fromFile(ToolHelper.getCHMOnlyDesugarLibJsonForTesting()));
+  }
+}
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 02d036c..c7544d5 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
@@ -41,13 +41,22 @@
   }
 
   @Test
-  public void testDesugaredLibraryContent() throws Exception {
+  public void testDesugaredLibraryContentD8() throws Exception {
     Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
     CodeInspector inspector = new CodeInspector(buildDesugaredLibrary(parameters.getApiLevel()));
     assertCorrect(inspector);
   }
 
   @Test
+  public void testDesugaredLibraryContentR8() throws Exception {
+    Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
+    CodeInspector inspector =
+        new CodeInspector(
+            buildDesugaredLibrary(parameters.getApiLevel(), "-keep class * { *; }", true));
+    assertCorrect(inspector);
+  }
+
+  @Test
   public void testDesugaredLibraryContentWithCoreLambdaStubsAsProgram() throws Exception {
     Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
     ArrayList<Path> coreLambdaStubs = new ArrayList<>();
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
index 4e96f57..b3d3ddd 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getEmulateLibraryClassNameSuffix;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertTrue;
@@ -14,7 +15,6 @@
 import com.android.tools.r8.code.Instruction;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
@@ -75,11 +75,7 @@
 
   private List<FoundClassSubject> getEmulatedInterfaces(CodeInspector inspector) {
     return inspector.allClasses().stream()
-        .filter(
-            clazz ->
-                clazz
-                    .getOriginalName()
-                    .contains(InterfaceMethodRewriter.EMULATE_LIBRARY_CLASS_NAME_SUFFIX))
+        .filter(clazz -> clazz.getOriginalName().contains(getEmulateLibraryClassNameSuffix()))
         .collect(Collectors.toList());
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
index 131295c..f9d1828 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
@@ -68,9 +68,7 @@
         .inspectDiagnosticMessages(this::assertDiagnosis)
         .addRunClasspathFiles(customLib)
         .run(parameters.getRuntime(), Executor.class)
-        .assertFailureWithErrorThatMatches(
-            containsString(
-                "conversion was impossible because of the non convertible type java.time.Year"));
+        .assertFailureWithErrorThatMatches(containsString("NoSuchMethodError"));
   }
 
   private void assertDiagnosis(TestDiagnosticMessages d) {
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MethodParametersTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MethodParametersTest.java
index 30dc93f..236cf7e 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MethodParametersTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MethodParametersTest.java
@@ -91,9 +91,9 @@
             parameters.isCfRuntime(),
             result ->
                 result.assertSuccessWithOutputLines(
-                    "int, int, Outer$Inner-IA, 3",
-                    "int, Outer$Inner-IA, 2",
                     "Outer$Inner-IA, 1",
+                    "int, Outer$Inner-IA, 2",
+                    "int, int, Outer$Inner-IA, 3",
                     "int, int, 2",
                     "int, 1",
                     "0"),
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromStaticInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromStaticInterfaceMethodTest.java
index 5660355..e1763f1 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromStaticInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromStaticInterfaceMethodTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize.outliner;
 
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
@@ -12,7 +13,6 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
@@ -65,8 +65,7 @@
                     .getApiLevel()
                     .isGreaterThanOrEqualTo(apiLevelWithStaticInterfaceMethodsSupport())
             ? inspector.clazz(I.class)
-            : inspector.clazz(
-                I.class.getTypeName() + InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX);
+            : inspector.clazz(I.class.getTypeName() + getCompanionClassNameSuffix());
     assertThat(interfaceSubject, isPresent());
 
     MethodSubject greetMethodSubject = interfaceSubject.uniqueMethodWithName("greet");
diff --git a/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java b/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java
index 2875a43..36a35e5 100644
--- a/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java
+++ b/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java
@@ -3,11 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.jasmin;
 
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertFalse;
 
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -37,8 +37,7 @@
     AndroidApp androidApp = compileWithD8(builder);
 
     CodeInspector codeInspector = new CodeInspector(androidApp);
-    ClassSubject clazz =
-        codeInspector.clazz("MyAnnotation" + InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX);
+    ClassSubject clazz = codeInspector.clazz("MyAnnotation" + getCompanionClassNameSuffix());
     assertThat(clazz, isPresent());
     assertFalse(clazz.isAnnotation());
   }
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
index cae1185..1868602 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
@@ -84,9 +84,11 @@
     assertTrue(inspector.clazz(LibraryInterface.class).isPresent());
     assertTrue(inspector.method(LibraryInterface.class.getMethod("foo")).isPresent());
     if (willDesugarDefaultInterfaceMethods(parameters.getApiLevel())) {
-      ClassSubject companion = inspector.clazz(Reference.classFromDescriptor(
-          InterfaceMethodRewriter.getCompanionClassDescriptor(
-              classFromClass(LibraryInterface.class).getDescriptor())));
+      ClassSubject companion =
+          inspector.clazz(
+              Reference.classFromDescriptor(
+                  InterfaceDesugaringForTesting.getCompanionClassDescriptor(
+                      classFromClass(LibraryInterface.class).getDescriptor())));
       // Check that we included the companion class.
       assertTrue(companion.isPresent());
       // TODO(b/129223905): Check the method is also present on the companion class.
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
index 961d400..19b87e4 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.shaking.ifrule.interfacemethoddesugaring;
 
-import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPublic;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isStatic;
@@ -74,7 +74,7 @@
             .inspector();
 
     ClassSubject classSubject =
-        inspector.clazz(Interface.class.getTypeName() + COMPANION_CLASS_NAME_SUFFIX);
+        inspector.clazz(Interface.class.getTypeName() + getCompanionClassNameSuffix());
     assertThat(classSubject, isPresent());
     assertEquals(2, classSubject.allMethods().size());
 
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
index 1b4ec31..6ffbce9 100644
--- a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
@@ -5,7 +5,7 @@
 
 import static org.hamcrest.CoreMatchers.containsString;
 
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.Reference;
@@ -22,7 +22,7 @@
 
   public static ClassReference syntheticCompanionClass(Class<?> clazz) {
     return Reference.classFromDescriptor(
-        InterfaceMethodRewriter.getCompanionClassDescriptor(
+        InterfaceDesugaringForTesting.getCompanionClassDescriptor(
             Reference.classFromClass(clazz).getDescriptor()));
   }
 
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index 4f8ecd3..8beec8a 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
 
 import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.graph.DexMethod;
@@ -232,7 +232,9 @@
     String descriptor = reference.getDescriptor();
     return codeInspector.clazz(
         Reference.classFromDescriptor(
-            descriptor.substring(0, descriptor.length() - 1) + COMPANION_CLASS_NAME_SUFFIX + ";"));
+            descriptor.substring(0, descriptor.length() - 1)
+                + getCompanionClassNameSuffix()
+                + ";"));
   }
 
   public abstract RetraceClassResult retrace();
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index 0533c6b..77c68b3 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.utils.codeinspector;
 
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
+
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.TestDiagnosticMessagesImpl;
@@ -24,7 +26,6 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.SwitchPayloadResolver;
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.naming.ClassNamingForNameMapper;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -327,9 +328,7 @@
   }
 
   public ClassSubject companionClassFor(Class<?> clazz) {
-    return clazz(
-        Reference.classFromTypeName(
-            clazz.getTypeName() + InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX));
+    return clazz(Reference.classFromTypeName(clazz.getTypeName() + getCompanionClassNameSuffix()));
   }
 
   public void forAllClasses(Consumer<FoundClassSubject> inspection) {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index 268c51a..d781ef5 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getDefaultMethodPrefix;
 
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfPosition;
@@ -372,7 +372,7 @@
             .build();
     return companionClass.method(
         reference.getReturnType().getTypeName(),
-        DEFAULT_METHOD_PREFIX + reference.getMethodName(),
+        getDefaultMethodPrefix() + reference.getMethodName(),
         p);
   }
 }
diff --git a/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1 b/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1
index cb35cd0..64f4609 100644
--- a/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1
+++ b/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1
@@ -1 +1 @@
-5696c90f0675746b4e996c80de461dd2cfd80076
\ No newline at end of file
+112c4e2bbfdd1e825ee02a98416ba385ad5433d0
\ No newline at end of file
diff --git a/tools/archive_desugar_jdk_libs.py b/tools/archive_desugar_jdk_libs.py
index 2bc8386..d2c1ef1 100755
--- a/tools/archive_desugar_jdk_libs.py
+++ b/tools/archive_desugar_jdk_libs.py
@@ -104,7 +104,7 @@
           checkout_dir, 'bazel-bin', 'src', 'share', 'classes', 'java', 'libjava.jar')
     else:
       library_jar = os.path.join(
-          checkout_dir, 'bazel-bin', 'jdk11', 'src', 'java_base_selected.jar')
+          checkout_dir, 'bazel-bin', 'jdk11', 'src', 'd8_java_base_selected.jar')
     maven_zip = os.path.join(
       checkout_dir,
       'bazel-bin',